Since the Java Card heap is in persistent memory, GC takes some time and some platform implementations are using very specific trigger to launch gc (e.g. memory almost full, or operation know to create garbage like application uninstall) instead of regularly trying to launch it.
In an application, you can use JCSystem.requestObjectDeletion() to schedule the gc. For performance reasons, you understand that you should use it only when you know you created garbage. The gc will get launched before the next call to Applet.process().
In addition, in order to reduce pressure on GC (and on persistent memory), I would also recommend to manage independently the total file size (size allocated in persistent memory, which could be the data.length ) from actual data size in the file (length field). You could for example extend your file by bigger chunks (64b or 128b each) and just increase the length by the real number of data written.
Also, don't forget that the heap is persistent, so make sure that any field that do not need to survive across sessions (power-down/power-up) is in volatile memory (RAM). I'm referring here to your 'ptr' which looks like to be the current reading position in the file but does not seem to be something that need to be persistent. If you need to have fields in RAM, consider using a specific context object, internally using one of the JCSystem.makeTransient<...>Array() methods.
I hope this will help!
If requesting garbage collection doesn't work then completely remove card from field. Some implementations require a full power down and some reader implementations may not always remove the field even on a hard reset.