[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference pamsrc::objectbroker_development

Title:ObjectBroker Development - BEA Systems' CORBA
Notice:See note 2 for kit locations; note 4 for training
Moderator:RECV::GUMBELd
Created:Thu Dec 27 1990
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:2482
Total number of notes:13057

2456.0. "return values and out arguments, memory management" by STKAI1::LANKI_T (Tapio Lanki) Tue Mar 18 1997 07:51

    I've been trying to understand the issues in memory
    management in C++ (OBB 2.7-11). Now follows a lot of 
    text, but only a few, simple (?) questions!!!
    
    What I want to clarify, is the difference between 
    OUT parameters and return values when returning a
    sequence.
    
    Reading the "OBB Designing and Building Applications"
    section 11.4.5 I understand the following:
    
    (Table 11-3, key # 3) For OUT arguments the caller
    (e.g., my client program) allocates a pointer etc etc.
    The callee sets the pointer etc etc. OBB then releases
    the memory on the callee side (after the statement
    "return _method_result")! CORRECT????
    
    For return values, the key# 3 says: "The callee returns
    a pointer as for OUT arguments". My interpretation (PLS
    correct me if I'm wrong) is that I have to allocate 
    memory on the server side, and return a pointer to that
    piece of memory??
    
    Question 1. I assume that OBB releases that piece of
    memory after the statement "return _method_result" as
    for OUT arguments?
    
    Question 2. I can allocate memory for the sequence in 
    two ways:
    a) either by using the constructor "InfoSequence (CORBA::ULong _max,
    CORBA::ULong _length, Info *_value, CORBA::Boolean _relse
    = CORBA_FALSE)"
    b) allocbuf (CORBA::ULong _nelems)
    CORRECT??
    In case a), does OBB release the memory?
    In case b), do I have to use freebuf (that's how I understand
    the documentation)?
    
    
    Hope the questions were clear enough? I certainly have 
    enough problems to understand what I mean myself.
    
    Still learning (as always),
    Tapio Lanki
    Digital Consulting, Stockholm
T.RTitleUserPersonal
Name
DateLines
2456.1LEMAN::DONALDSONFroggisattva! Froggisattva!Fri Mar 21 1997 08:4155
Tapio,

my understanding (still learning like you) is that if
you set the release flag to false then you you are
responsible for the memory.

Below is an example of a method for an unbounded sequence
of unbounded strings. It seems to work fine.

John D.

------------------------------------------------
 void i1Impl::i1Impl_OUseqUstr (
    CORBA::Long totalUseq,
    CORBA::Long totalUstr,
    m1::tUseqUstr *& oseq,
    CORBA::Environment & ev)

{

/* OBB_PRESERVE_BEGIN(i1Impl::i1Impl_OUseqUstr) */
         cout << endl << "Entering i1Impl::i1Impl_OUseqUstr" << endl;
         cout << "    totalUseq=" << totalUseq << endl;
         cout << "    totalUstr=" << totalUstr << endl;

        // create the buffer of the sequence
        CORBA::Char **seqBuffer = m1::tUseqUstr::allocbuf( totalUseq);

        // make strings and build them into the sequence buffer
        for (short i=0; i<totalUseq; i++)
        {
                CORBA::Char *str = CORBA::string_alloc (totalUstr);
                if (str == 0)
                {
                        cout << "Failed to allocate string totalUstr " << 
				totalUstr << endl;
                }
                else
                {
                        for (short j=0; j<totalUstr; j++)
                        {
                                str[j] = 'a';
                        }
                        str[totalUstr] = '\0';
                }
                (seqBuffer)[i] = str;
        }

        // construct the sequence
        oseq = new m1::tUseqUstr( totalUseq, totalUseq, seqBuffer, CORBA_TRUE);
         
/* OBB_PRESERVE_END(i1Impl::i1Impl_OUseqUstr) */
    return ;
}

2456.2REQUE::BOWERPeter Bower, ObjectBrokerTue Apr 01 1997 07:394
    You can also set the length or maximum which will allocate the
    memory.
    
    
2456.3C++ memory handling revisitedSTKAI1::LANKI_TTapio LankiWed Apr 02 1997 09:47134
    
    
    This issue was more difficult than I thought.
    We have these questions/problems in a customer
    project (urgent, as always) and I cannot give the
    answer.
    
    I appreciate some quick feedback.
    
    /Tapio Lanki
    
    
    In .1 John wrote about his example
    "an unbounded sequence of unbounded strings."
    
    Our problem can be defined as (see the IDL code below)
    - unbounded sequence of structures, each containing 
    	- unbounded strings
    	- short
    	- an unbounded sequence of structures, each containing
    		- short 
    		- string
    
    I've attached the IDL code, and some sample code generating memory
    leaks (this obviously not being the correct way to do it...)!
    
    Questions
    
    Q1: The structures must be created using new. In order to avoid
    memory leaks, we should use delete somewhere! But not having the
    execution thread makes this impossible. 
    
    Q2: In the sample code, every *new* creates a number of structures, 
    which can be passed to the constructor of the sequence according 
    to .1! Is the strategy wrong?
    
    Q3: Objects contain the member function allocbuf. In .1 the
    seqBuffer is created using allocbuf, and later passed as a 
    parameter to a constructor (creating the sequence), together
    with CORBA_TRUE. How is this achieved for structures?
    Should we use the _var classes? How, in this case?
    
    Q4: May a sequence be created with zero number of
    elements? (In this context, OW_MPInfo may contain
    information in the structure, but the sequence in the
    structure may be empty!)
    
    
    
    IDL (edited for simplicity)
    ===========================
    module PIX
    {
        // This module contains an unbounded sequence of OW_MPInfo
        // structures. Each of these structures contains an
        // unbounded sequence of OW_Speprov structures.
    
        
        // Forward declarations
        interface PIXManager;
    
        struct OW_Speprov 
        {
            short SegmentNumber;
            string Type;
        };
    
        typedef sequence <PIX::OW_Speprov> OW_Speprov_Seq;
    
        struct OW_MPInfo 
        {
    	  string Description;
            long IdentificationNumber;
            string InputDate;
            PIX::OW_Speprov_Seq Speprov;
        };
    
        typedef sequence <PIX::OW_MPInfo> OW_MPInfo_Seq;
    
        interface PIXManager 
        {
            PIX::OW_MPInfo_Seq searchMasterPlan(in string searchCriteria);
        }; // end of interface PIXManager
        
    }; // end of module PIX
    
    
    
    
    
    
    sample code
    ===========
    PIX::OW_MPInfo_Seq* CPIXConverter::Convert()
    {
    	PIX::OW_MPInfo* paMPInfo=new PIX::OW_MPInfo[ulMPCount];
    	for(unsigned long ulIndex=0;ulIndex<ulMPCount;++ulIndex)
    	unsigned long
    ulMPCount=(m_pMgr->m_wmapMasterPlanSorted).GetCount();
    	{
    		CObject* pO=NULL;
    		(m_pMgr->m_wmapMasterPlanSorted).Lookup((WORD)ulIndex,pO);
    		
    (paMPInfo+ulIndex)->IdentificationNumber=(CORBA::Long)((CMasterPlan*)pO)->GetIdentificationNumber();
    		
    (paMPInfo+ulIndex)->Description=Move(((CMasterPlan*)pO)->GetDescription());
    		
    (paMPInfo+ulIndex)->InputDate=Move(((CMasterPlan*)pO)->GetInputDate());
    	
    		PIX::OW_Speprov* pS=new
    PIX::OW_Speprov[((CMasterPlan*)pO)->GetNumberOfTestSpecifications()];
    		
    for(i=0;i<((CMasterPlan*)pO)->GetNumberOfTestSpecifications();++i)
    		{
    			
    (pS+i)->SegmentNumber=(CORBA::Short)((CMasterPlan*)pO)->GetSegmentNumber(i);
    			(pS+i)->Type=Move(((CMasterPlan*)pO)->GetType(i));
    		}
    		PIX::OW_Speprov_Seq* pSeq=new PIX::OW_Speprov_Seq(
    				
    ((CMasterPlan*)pO)->GetNumberOfTestSpecifications(),((CMasterPlan*)pO)->GetNumberOfTestSpecifications(),
    				pS);
    			(paMPInfo+ulIndex)->Speprov=*pSeq;
    	}
    	PIX::OW_MPInfo_Seq* pMPISeq=new PIX::
    OW_MPInfo_Seq(ulMPCount,ulMPCount,paMPInfo);
    	return pMPISeq;
    }
    CORBA::String_var CPIXConverter::Move(CString str)
    {
    	char* pStr=CORBA::string_alloc(str.GetLength()+1);
    	strcpy(pStr,str);
    	return pStr;
    }
2456.4REQUE::BOWERPeter Bower, ObjectBrokerWed Apr 02 1997 11:1893
    
    > Q1: The structures must be created using new. In order to avoid
    > memory leaks, we should use delete somewhere! But not having the
    > execution thread makes this impossible. 
    
    The ORB releases the memory for out, inout, and return parameters.
    That is why you have to call the appropriate function to allocate
    the memory (string_alloc for strings, new for structs,unions,
    allocbuf). The following happens - OBB marshalls up all the data
    to be returned to the client. It then goes through all the parameters,
    cleaning up. It releases all the in data allocated by the ORB, and
    all the out data (inout, out, return) allocated by the user.
    
    With the C++ Binding, all nested members manage their own memory.
    Therefore, one delete on the sequence class will release all the
    memory associated with sequence. Strings are managed by String_vars
    in the generated code. Nested sequences are classes with their
    own destructor.
    
    > Q2: In the sample code, every *new* creates a number of structures, 
    > which can be passed to the constructor of the sequence according 
    > to .1! Is the strategy wrong?
    
    With a sequence, you can either use the default constructor or a
    constructor that allows you to specify the buffer for the sequence.
    If you specify a buffer, then the buffer must have been allocated
    using the allocbuf function. Optionally, you can set the length
    and the buffer will be allocated for you. 
    
    > Q3: Objects contain the member function allocbuf. In .1 the
    > seqBuffer is created using allocbuf, and later passed as a 
    > parameter to a constructor (creating the sequence), together
    > with CORBA_TRUE. How is this achieved for structures?
    > Should we use the _var classes? How, in this case?
    
    For structures, you use new. You use the _var class if you want
    the structure to be automatically released when the _var goes out of
    scope.
    
    > Q4: May a sequence be created with zero number of
    > elements? (In this context, OW_MPInfo may contain
    > information in the structure, but the sequence in the
    > structure may be empty!)
    
    The default constructor for an unbounded sequence will create a
    sequence with zero elements. You need to call length before accessing
    any element, but it is ok to have a zero length sequence.
    
    >
    > One way of doing the initialization is as follows (not actually
    > compiled), but this should provide a hint.
    > I believe you were getting leaks from not deleting the allocated 
    > Speprov sequence after doing the assignment. Other changes I made
    >  - use string_dup instead of Move
    >  - use length and [] instead of assignment operator, you could also
    >    do this for the top-level sequence if you desire.
    >
    
    PIX::OW_MPInfo_Seq* CPIXConverter::Convert()
    {
    	PIX::OW_MPInfo* paMPInfo= PIX::OW_MPInfo_Seq::allocbuf(ulMPCount);
    	for(unsigned long ulIndex=0;ulIndex<ulMPCount;++ulIndex)
    	unsigned long ulMPCount=(m_pMgr->m_wmapMasterPlanSorted).GetCount();
    	{
    	    CObject* pO=NULL;
    	    (m_pMgr->m_wmapMasterPlanSorted).Lookup((WORD)ulIndex,pO);
    		
            (paMPInfo+ulIndex)->IdentificationNumber=(CORBA::Long)
    		((CMasterPlan*)pO)->GetIdentificationNumber();
    		
	    (paMPInfo+ulIndex)->Description=CORBA::string_dup
    			(((CMasterPlan*)pO)->GetDescription());
    		
    	    (paMPInfo+ulIndex)->InputDate=CORBA::string_dup
    			(((CMasterPlan*)pO)->GetInputDate());
    	
	    (paMPInfo+ulIndex)->Speprov.length(
    			(CMasterPlan*)pO)->GetNumberOfTestSpecifications());
    	
    	    for(i=0;i<((CMasterPlan*)pO)->GetNumberOfTestSpecifications();++i)
    		{
	    	(paMPInfo+ulIndex)->Speprov[i].SegmentNumber=
    			(CORBA::Short)((CMasterPlan*)pO)->GetSegmentNumber(i);
    	    	(paMPInfo+ulIndex)->Speprov[i].Type=
    			CORBA::string_dup(((CMasterPlan*)pO)->GetType(i));
    		}
    	}
    
    	PIX::OW_MPInfo_Seq* pMPISeq=new 
    		PIX::OW_MPInfo_Seq(ulMPCount,ulMPCount,paMPInfo);
    	return pMPISeq;
    }
    
2456.5Checking for memory leaks in NT4.0STKAI1::LANKI_TTapio LankiThu Apr 03 1997 03:0223
    Hmm, maybe we should have done things in different order...
    
    The environment is:
    - NT4.0, service pack 2
    - VC++4.2 (not 4.0)
    - OBB 2.7-11
    
    In .4 Peter Bower wrote
    "OBB marshalls up all the data to be returned to the client. 
    It then goes through all the parameters, cleaning up. It releases 
    all the in data allocated by the ORB, and all the out data 
    (inout, out, return) allocated by the user"
    
    So, the question is: How should we check for memory leaks in
    our environment? 
    
    We did it like this: After the debugging session the debugger
    reported the results of the memory usage. But, if OBB frees 
    the memory, can the debugger detect this? Should we use
    an external tool to be 100 per cent sure?
    
    Tapio Lanki
    Digital Consulting (on a customer site)
2456.6REQUE::BOWERPeter Bower, ObjectBrokerThu Apr 03 1997 08:434
    
    I like purify - it runs on NT and is very easy to use.
    
    
2456.7LEMAN::DONALDSONFroggisattva! Froggisattva!Mon Apr 07 1997 09:385
If all you want is a dynamic view on the memory used by a 
program, then the Task Manager of NT4 works well.

John D.