Thread class memory allocation oddity on an embedded platform
Asked Answered
H

1

6

I am running into a strange issue I've been able to track down somewhat but I still can't see the cause. Maybe someone here can shed some light?

I'm running on a PowerPC processor on top of VxWorks 5.5 developing in C++ with the PPCgnu604 toolchain.

I have a class like so:

class MyClass
{
  public:
    void run( void );
  private:
    CommandMesssageClass command;
    StatusMessageClass status;
};

When my application is started, it will dynamically allocate an instance of MyClass and spawn a thread pointing to its "run" function. Essentially it just sits there polling for commands and, upon receipt, will issue a status back.

Note that this is a chopped down version of the class. There are a number of other methods and variables left out for brevity.

The issue I see is when both the command and status messages are defined as private class members I will get a change in the available bytes in memory despite the fact there should be no dynamic memory allocation. This is important because this is ocurring in what needs to be a deterministic and rate-safe procedure.

If I move one or both of the message declarations into the run function, it works fine with no additional allocation!

I must be missing something fundamental in my understanding of C++ declarations and memory allocation. My understanding is that a class instance that I dynamically instansiate will be fully allocated on the heap (including all member variables) when it's created. The difference I see here would be that moving the message declarations to the run function puts them on the stack instead. The heap in this case is more than large enough to accompadate the entire size of the class. Why does it seem not to be allocating enough memory until specific portions are used?

The message classes do no dynamic allocation of their own. (And if they did, I would expect moving the declaration would not change the behavior in this case and I would still see a change in the size of the heap.)

To monitor the memory allocation I'm using the following VxWorks memLib (or memPartLib) call:

memPartInfoGet( memSysPartId, &partitionStatus );
...
bytesFree = partitionStatus.numBytesFree;

Edit:

To clarify, the MyClass object is instansiated and initialized in an initialization routine and then the code enters rate-safe processing. During this time, upon the receipt of a command message over a serial line (the first interaction with the Command or Status message objects) additional memory is allocated (or rather the number of bytes free decreases). This is bad because dynamic memory allocation is not deterministic.

I've been able to get rid of the problem by moving the class variables as I've described.

Honora answered 2/8, 2010 at 22:30 Comment(9)
It's not entierly clear what your problem is, is it that you use more memory allocating the stuff as class members vs on the stack , or is it that the used memory varies over time in one of the cases ?Volar
Does sizeof(MyClass) change when you lift the members to the public section? And how much does the memory allocation change?Photophilous
When does the allocation change? Smaller class objects have an easier time fitting in a free block on the heap.Numismatics
I've edited the original post hopefully to clarify the problem. nos: The problem is that dynamic memory allocation occurs during rate-safe processing, and memory allocation is not deterministic. Everything should be allocated on initialization, and then you just worry about blowing the stack. Luther: The memory allocation changes by 80 bytes each time. I will look at sizeof today. Hans: The object is initialized at the start and changes during in processing loop when a serial command is received. The command is then copied into the CommandMessageClass object to be decoded.Honora
Luther: The size of the MyClass object decreases from 608 to 256 (the drop is correctly the combined sizes of the two objects I moved) when they're moved to the run function.Honora
Your understanding of C++ allocation semantics is correct, at least -- there's something else going on here, perhaps in the portions of the code you haven't shown. How are messages getting to the thread class? How is the thread polling for them?Reimport
@Anthony: does MyClass need to be on the heap? Can you put it in bss?Crowe
@Anthony: I concur that your grasp of allocation semantics is correct, how are the to member variables accessed? 2nd: If you keep the two members private, but look at their memory-adresses at run-time and compair to the memory-address of the MyClass instance, what do you get?Crandale
You said the memory allocation in your comment changes by 80 bytes. Is the size of your StatusMessageClass 80 bytes?Mauve
N
2

I must be missing something fundamental in my understanding of C++ declarations and memory allocation.

I don't think so. Everything you say that you expect above is correct -- game programmers rely heavily on this behavior all the time. :-)

Why does it seem not to be allocating enough memory until specific portions are used?

You've left out the guts of the class for brevity. I've had some experience debugging similar issues, and my best guess is that somewhere in there a library function is, in fact, making a runtime allocation that you don't know about.

In other words, the runtime allocation is there in both cases, but the two different sizes of MyClass mean that the malloc pools are filled differently. You could prove this by moving the objects to the stack inside run(), but padding MyClass out to the same size. If you still see the free mem drop, then it has nothing to do with whether those objects are on the heap or the stack ... it's a secondary effect that's happening because of the size of MyClass.

Remember, malloc is chunky -- most implementations don't do one-to-one allocations for each call to malloc. Instead it over-allocates and keeps the memory around in a pool, and grows those pools when necessary.

I'm not familiar with your toolchain, but typical suspects for unexpected small allocations on embedded systems include ctype functions (locales), and date/time functions (time zone).

Niobium answered 18/8, 2010 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.