[java] Reachability of temporaries

Started by
1 comment, last by SamLowry 18 years, 4 months ago
For an assignment I have to write a few audio filters using the javax.sound.sampled package. You are given bytes, which you have to combine into samples, then separate the channels, apply the filters, interleave the channels and finally convert it back to bytes. To me it seems most natural to represent all this data using linked lists. (Using streams is also possible, but it's a bit more bothersome, as the original data stream is ephemeral (can only be read once), and hence buffers are needed, and I'd prefer to have something cleaner than that) Using "regular" linked lists is quite expensive in terms of memory though, so I tried implementing Haskell's lazy lists in java: cons-cells are only constructed when actually needed. I also rely on the fact that cons-cells which are not needed anymore become unreachable and can be reclaimed by the GC. This way, I can code my filters as if I were working on regular linked lists, while in reality only a small fraction of the list exists in memory. However, I bumped into unexpected behavior:

LazyList<Byte> loadByteList(String file);
LazyList<Byte> applyFilters(LazyList<Byte> input);

LazyList<Byte> output = applyFilters( loadByteList("input.wav") );
It seems the cons-cell loadByteList returns still exists while applyFilters is running so that it is still reachable and hence no cons-cells can be reclaimed by the GC, resulting in high memory consumption (and slowdowns due to the frequent GC-cycles, after which a OutOfMemory error gives the coup de grâce). So, in a way, temporaries stay reachable beyond their lifetime. I've checked if other 2 languages behave like this: OCaml and C# do not to seem to have this problem. This leads me to the following two questions: a) is there a specific reason java wants temporaries to remain reachable? b) is there an easy way to detect which objects are reachable so that I can quickly find the culprit when I run into this kind of situation again?
Advertisement
I'm guessing that it's in the 'Invisible' lifecycle state. Apparently, try {...} catch {...} blocks can also create this problem. link

Keeping track of your lists with weak references might help you at least track down the source of future problems. I've never had to do this myself so I don't know what's involved - this link might have some useful information though.
I didn't know about the invisible references, I guess my problem falls under that category. I find it strange that optimisations that can lead to memory leaks are allowed, GC becomes quite a leaky abstraction this way.

Thank you for your links and suggestions.

This topic is closed to new replies.

Advertisement