There's no set in stone rules. I would recommend the following:
Static Array:
If you know the size of what you are allocating and can statically allocate it, then use this. This is typically the safest way because there is definite storage for it and you can see it clearly in your map file. Bad pointers can obviously still mess this up but at least every thing has its own reserved space.
Packet Pool Array:
Packet pools are specifically for NetX but I'm guessing you mean dynamic memory allocation from the RTOS. For ThreadX this would be byte and block pools. These are good to use when you cannot statically allocate the memory you need, or there is a good reason to not use static allocation (eg efficiency). Whether you use byte or block pools will depend on your application but I would recommend you use block pools if you can since with byte pools you have to worry about fragmentation.
I would definitely recommend you use the RTOS pools instead of malloc(), free(), etc
first_unused_memory:
This is used for demos because you don't know the part you are running on and you don't have to statically allocate anything. It also offers the promise of using that wasted RAM space that is not allocated to anything. I cannot think of a use case where I would recommend someone use this in their application. The main issue here is that since this is just a pointer into non-allocated RAM, you don't know when building the your project if you've run out of RAM. You could just be running your code, get a hard fault, and then you have figure out why. You won't be able to see the problem in your map file because nothing is allocated. Why take the risk? Just go ahead an allocate the memory.