the main problem with direct allocated buffers is that they can’t be allocated everywhere. In fact they are allocated somewhere in the permgen (-> not in the regular heap) which limits the max usable amount of memory.
(remember direct memory does not change the position which has advantages and disadvantages. e.g fragmentation, but on the other hand this makes them to the best vehicle to transfer mem between jvm and native libs)
@see -XX:MaxDirectMemorySize=foobar
if you are running out of direct memory (on latest JREs) you will see the info usually in the exception message.
as riven said, use big buffers and slice them and prevent allocating direct buffers again and again.
[edit] latest version of visualvm + jre6 can track direct memory usage, nice tool for debugging.