as the title suggests :D

obviously i cant use interrupts...so how would i go abt doing sumthing like that...or would i just have to set aside space in the data section...fanks
Posted on 2003-04-23 23:36:32 by AnotherWay83
AnotherWay83,

Win32 is in fact well endowed with memory allocation functions and they can be tailored more or less to what you require. With lots of small allocations GlobalAlloc() has the correct granularity as does the OLE string memory functions, if you want access to the heap memory, HeapAlloc() works fine and you can allocate system memory with a memory mapped file which is of global scope which is very useful for inter app communication.

Regards,

hutch@movsd.com
Posted on 2003-04-24 01:01:20 by hutch--
There is no "global" memory in win32 - GlobalAlloc allocates heap memory, too. On NT it even ends up in HeapAlloc (with some special flags). You're better off using HeapAlloc for all generic allocations - that way you can also specify your own heap, if you want to (GetProcessHeap is best for "normal" stuff though).

For "special needs", VirtualAlloc. You can reserve memory and not commit it until necessary that way. You get 64k allocation granularity, so for large stuff like framebuffers, valloc would be a good thing too. It's a slow routine though, so only suitable for a few large allocs, or specialized stuff such as controlling reserve/commit. Also useful if you need special page protection flags.

Memory Mapped files are good if you need to share memory between processes. It's also the only way to do that. For all other purposes, stay way from it, as memory access speed is somewhat slower with these - and the allocation overhead is very large, too. There's other problems with these, too, especially on 9x (because of the horrible private/global address space split on 9x systems).

Stay away from the "OLE String" memory functions hutch talk about, they're made for strings, not generic memory allocs. Seems silly to use them. If you want other methods, look at CoTaskMemAlloc, or the IMalloc interface, etc.

Generally, my advice is to go with HeapAlloc unless you need one of the other methods.
Posted on 2003-04-24 02:04:06 by f0dder
Anotherway83,

Try this one:




.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
includelib msvcrt.lib

printf PROTO C a1:DWORD,a2:VARARG
malloc PROTO C :DWORD
free PROTO C :DWORD

.data
msg db 'pMemory=%X',0
.code
start:
invoke malloc,100
push esi
mov esi,eax
invoke printf,addr msg,esi
invoke free,esi
pop esi
invoke ExitProcess,0
end start

Posted on 2003-04-24 03:44:53 by Vortex
f0dder,

you are technically wrong in restricting OLE memory to one application type, it works just as well in arrays, video, general purpose data and is particularly useful where there are many small allocations.

Finally memory is memory, if you can read and write to it, it does the job and avoiding one particular type on a person disposition is a mistake.

OLE string memory is both fast allocation and easy to use in a range of sizes.

Regards,

hutch@movsd.com
Posted on 2003-04-24 04:01:16 by hutch--
Your ole string functions are made for string, and allocation thus has more overhead than just allocation the memory. If there's other "ole memory" functions, those would probably be files - but imho it's silly using string functions for memory.


Finally memory is memory, if you can read and write to it, it does the job and avoiding one particular type on a person disposition is a mistake.

The various routines have different allocation- and access-speed parameters though. This matters especially for VirtualAlloc and MMF.

Most of (if not all) the other routines end up allocating heap memory, even using HeapAlloc for it - so you might as well use the shortest route and do HeapAlloc. If you don't like specifying all those parms to HeapAlloc, fine, write your own simple-interface wrapper around it.

I believe IMalloc and CoTaskMemAlloc(which is just a wrapper around the IMalloc interface) memory had memory pooling, something that can speed up when you have lots of allocs/deallocs. Possibly ole strings had too - but again, ole strings also does stuff related to string conversion etc.
Posted on 2003-04-24 04:06:01 by f0dder
Oh, and please don't see this as "f0dder says B because hutch says A". My statements are based on theory as well as imperical observations. I've done quite some researching on this - unfortunately, I think I forgot to update my site with the findings, so it is probably scattered around a lot of posts on this board. I'll probably do all the research again and write up a detailed essay to clear any misconceptions, but here's a short roundup.
P is PSDK, F is my comments.

Global/LocalAlloc:
P: don't use local/globalalloc, they're deprecated
F: they end up allocation heap memory anyway.

VirtualAlloc:
F: slow allocation, can't be "reallocated". Pros are that is has advanced management, page protection, and 64k granularity. Good for few really-large allocs, or "advanced stuff".

Memory Mapped Files:
F: slow allocation, somewhat slower access speed because of the underlying techniques. Big problems on 9x because MMF are allocated in the (very) limited global part of the address space. Also, paging file is forced to grow, since MMF are backed up by the paging file when not backed by a file handle. Only way to allocate "global" memory - so use it when you have to do this, and otherwise not.

SysAllocStringByteLen:
P: Allocates a new string of len bytes, copies len bytes from the passed string into it, and then appends a null character.
F: you don't have to specify the source string, effectively just alocating memory - however, it should still allocate one byte more, has a little additional overhead, and end up using heap memory anyway. Uses memory pooling which can speed up stuff when you have lots of allocs/deallocs - but rather than using this function just because of pooling, write your own decent code for this - gives more control. This routine *does* have a bunch of overhead, like messing around with TLS etc. Uses CoGetMalloc as backend allocator.

CoGetMalloc:
P: Retrieves a pointer to the default OLE task memory allocator (which supports the system implementation of the IMalloc interface) so applications can call its methods to manage memory.
F: returns a pointer to CoTaskMemAlloc.

CoTaskMemAlloc:
P: Allocates a block of task memory in the same way that IMalloc::Alloc does
F: wrapper around the IMalloc interface.

IMalloc interface:
You'll probably have to use this when dealing with COM. Allocated heap memory, possibly (can't remember) has pooling like SysAllocStringByteLen. Same speed (allocation/access) as heap memory, but doesn't let you specify flags like "HEAP_ZERO_MEMORY". Less control (can matter), overhead of calling through vtable (won't matter often - and in those cases, you're probably using your own heap anyway).
Posted on 2003-04-24 04:28:28 by f0dder
f0dder,

What about the malloc func. from the C run-time DLLs?
Posted on 2003-04-24 04:34:22 by Vortex
That will of course depend on the libc malloc implementation :) - it has to end up in OS memory routines, but there's of course a lot of different stuff libc can do to speed up stuff. vs.net libc basically ends up doing HeapAlloc, though, without too much extracode. I wouldn't depend on a libc malloc if I was writing asm apps. HeapAlloc==good :), IMalloc/CoTaskMemAlloc is fine and lets you _easily_ install spy/hook.

For normal code, I do C++, and thus use new or malloc. For specialized needs, I do specialized allocation routines - for instance pool memory allocation.
Posted on 2003-04-24 04:41:45 by f0dder
f0dder,

Thanks for the info.I guess,you are reading the disasm.
listing of these memory allocation functions to find the best
one.;)
Posted on 2003-04-24 04:47:25 by Vortex
Yes, I've been timing, tracing and disassembling, since PSDK didn't give "extensive" information. So of course some implementation details can differ on future systems. However, I think it shows that HeapAlloc is the best generic routine (gives you control, most direct path on current windows versions, and in the best speed class), followed by IMalloc if you need COM memory allocations or easy spying. And that the rest should be avoided unless you need to use them.
Posted on 2003-04-24 05:05:11 by f0dder
AnotherWay83,

You can make your own choice as to what you use without having to listen. Most of the functions are easy enough to use so just dial up what you want.

f0dder,

Your own testing previously that you posted in here about a year ago broke your own theory of allocation speed and with large numbers of small allocations, OLE string memory is just faster because its designed to do just that. Remember the PRE ALLOCATED characteristic of OLE string memory ?

Theories about how different versons of Windows handles memory does not give you priority of HeapAlloc() and if you remember, it was in fact slower because of its overhead, just like everyone else knows.

Now spare us this dogma, just reread your own testing posted here about a year ago.

Regards,

hutch@movsd.com
Posted on 2003-04-24 06:19:23 by hutch--
Appearantly you didn't read the previous postings nor the current.
If you would care to read the current post, you will see I have positive things to say about com string memory:

Uses memory pooling which can speed up stuff when you have lots of allocs/deallocs - but rather than using this function just because of pooling, write your own decent code for this - gives more control.

"preallocated memory" is nonsense, it's pooling. The same type that is done with HeapAlloc if you enable the "low fragmentation heap".


You can make your own choice as to what you use without having to listen. Most of the functions are easy enough to use so just dial up what you want.

So I'm telling him what to do and you're not? *cough*. At least I'm trying to give some reasons as to why I make the suggestions I do - it's up to people to make their own minds from that, and as with anything else, people shouldn't take anything for granted but do their own research.

---

I should really redo all this testing from scratch, along with a thorough explanation of the entire stuff. In one centralized place instead of scattered around multiple posts.
Posted on 2003-04-24 06:28:34 by f0dder
f0dder,

we have heard you own theories on memory allocation before and your own testing broke it. Anyone can come up with a memory allocation technique based on managing their own block of memory but this is not espousing the virtues of one technique over another, it replacing all of them with your own.

Pooled memory IS preallocated and this is how OLE string memory works, your own results also discovered this about a year ago.

Yawn.

hutch@movsd.com
Posted on 2003-04-24 06:35:11 by hutch--
Back then, the tone got rather hostile. Don't really want this again.
Yes, I made a some wrong guesses back then, and I corrected them.
The following isn't just directed to you, hutch - I assume you already know a lot of this, whether you agree with it or not. But there's a lot of other people on this board too :)


Pooled memory IS preallocated and this is how OLE string memory works, your own results also discovered this about a year ago.

Well, it's a question of definition perhaps? I understand it as "the memory is pre-allocated, so a low-level alloc func wont have to be called for first alloc". Iirc, the way the OLE string memory works, the pools are initially empty, but will of course be filled as you do allocations - this wont benefit you until you free a string and alloc afterwards, but that's generally the way pools work. I hope we're not arguing about term definition here :).

It also showed that for raw/initial allocations (ie, where the benefits of a pool wouldn't come into play), the OLEString was still a bit faster - but also that speeds were equal if I rounded memory request size to 16, like OLEString does.

I belive that should be fairly accurate, but I will do the tests again.

Now, the interesting point is... interface vs. implementation. You've been saying a bit about this yourself, and well... of course you shouldn't depend on implementation (I get the opinion that you agree on this by the previous posts?)

The OLEString doesn't guarantee that memory allocation is pooled, does it? If so, I have missed the point where this is stated. You can argue that this is unlikely to change, but then one can argue that the other memory routines are unlikely to change (et cetera).

If we look at only the interface, what PlatformSDK tells us, I get this impression:

- HeapAlloc allows more flexibility. You can specify the heap where you allocate, whether to get "random" or "zeroed" (will affect allocation speed), et cetera. OLEString doesn't let you, and the "NULL,size" way of allocating doesnt' say what the memory will be filled with - ie, undefined.

Also, you can't depend on the allocation granularity of neither HeapAlloc nor OLEString - the interface doesn't specify them.

So... if you want to rely on the interface, not the implementation, I would say it's smarter to use a flexible "low-level allocator" and implement your own aligned/pooled strategy ontop of this. That way you will get consistent results on current and future windows versions.

Why use HeapAlloc instead of some other "low-level" routine? After all, VirtualAlloc is far more lowlevel? Couple of reasons. HeapAlloc has HeapRealloc. HeapAlloc is listed as the preferred win32 method these days, so it's not unreasonable to guess that it won't be all messed up in the near future. Furthermore, HeapAlloc currently performs just as well as the other "low level" routines (when you don't take into account smarter strategies like pooling).

At least this makes sense to me?
Disassembly, tracing and timing empirically are good methods to get a general idea of how stuff performs, and I've used all these methods myself. However, this must not be used as a definitive guide on which to chose; if something isn't documented in the interface, you shouldn't rely on it, no matter how unlikely it seems it will be changed in the future. Yes, I sometimes forget about this too, I'm just human after all. But it's worth keeping in mind.

I'll try writing a "definitive" guide to this all, taking into account both what the interfaces say, and how it's done in the implementations. I have access to win2k, winxp, and win98se rigs, and will probably have a look at all of them. I hope I can come up with something crystal clear and objective, with some good explanations of my thoughts and code details. Will take some time, but I feel it ought to be done.
Posted on 2003-04-24 07:56:40 by f0dder
f0dder,

what about that "easy spying" of COM memory? Hopefully you dont mean that IMallocSpy stuff, which is really rubbish.

This memory pooling thing is true for this "SysAllocString" family, not for CoTaskMem/IMalloc. And its definitely not a good idea to use it (besides for BSTRs of course) because that makes finding memory leaks almost impossible.

Japheth
Posted on 2003-04-24 09:01:53 by japheth
I was referring to IMallocSpy, but didn't really read into it - what makes it rubbish?

Yes, seems like the pooling is only valid for the ole string stuff, my mistake. It's been a while since I messed with this last, and I tend to write my own stuff when I need things that aren't documented behaviour ;-)


Your point about memory leaks is a very good one - it's a good idea to write your own wrapper functions that can toggle between either normal or <whatever funky scheme> transperently in the internals. Debug version? Add debug code. Release version? use pooled memory or whatever other clever speed increasing scheme you can come up with :alright:
Posted on 2003-04-24 09:15:29 by f0dder
thanks everyone for ur replies, lots of interesting info, i have much to learn :D

thanks vortex for that code snippet, i didn't know u could use PROTO C...i guess that informs the assembler that its actually a C function...? i will read the docs for more info on that
Posted on 2003-04-24 14:05:16 by AnotherWay83
PROTO C tells ml.exe that the procdure is using the C calling convention and naming, in the help file \masm32\help\masm32.hlp there is an explanation of the different Calling Conventions.
Posted on 2003-04-24 14:55:23 by scientica
To answer the original question directly:


This is actual code generated by my compiler which in a previous generation was a c output compiler which used malloc() where VirtualAlloc is now used. The code before the VirtualAlloc is used to make sure that FileBuf was not already allocated. If it was, the memory is released and than reallocated. The commented lines are the user code that caused the code to be generated.



; LN:4609 BUFFER FileBuf=FilBufSiz
mov eax, dword [FilBufSiz]
push eax
cmp [FileBuf+4],0
je _Lbl777
invoke VirtualFree,[FileBuf],0,MEM_RELEASE
mov [FileBuf],0
mov [FileBuf+4],0
_Lbl777:
pop eax
mov [FileBuf+4],eax
invoke VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE
mov [FileBuf],eax
Posted on 2003-04-24 20:58:25 by msmith