T.R | Title | User | Personal Name | Date | Lines |
---|
2456.1 | | LEMAN::DONALDSON | Froggisattva! Froggisattva! | Fri Mar 21 1997 08:41 | 55 |
| 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.2 | | REQUE::BOWER | Peter Bower, ObjectBroker | Tue Apr 01 1997 07:39 | 4 |
| You can also set the length or maximum which will allocate the
memory.
|
2456.3 | C++ memory handling revisited | STKAI1::LANKI_T | Tapio Lanki | Wed Apr 02 1997 09:47 | 134 |
|
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.4 | | REQUE::BOWER | Peter Bower, ObjectBroker | Wed Apr 02 1997 11:18 | 93 |
|
> 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.5 | Checking for memory leaks in NT4.0 | STKAI1::LANKI_T | Tapio Lanki | Thu Apr 03 1997 03:02 | 23 |
| 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.6 | | REQUE::BOWER | Peter Bower, ObjectBroker | Thu Apr 03 1997 08:43 | 4 |
|
I like purify - it runs on NT and is very easy to use.
|
2456.7 | | LEMAN::DONALDSON | Froggisattva! Froggisattva! | Mon Apr 07 1997 09:38 | 5 |
| 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.
|