Another Forcing Java Garbage Collection Question (with *I think* a justifiable use case)
I have a data producer that produces data that is used by a number of a different consumers (let's call them Cs). Each C has its own set of data that it's interested in. The data producer has weak references to the Cs so they can be notified for updates.
Each C is also used by a number of independent components, so no single one component can tell when the C is no longer needed, so we have to leave it to the JVM to determine when C is GC-able.
The goal here is to be notified when a C becomes obsolete, so the data producer c开发者_开发百科an turn off data that is only interesting to that unused C.
As I mentioned earlier, the data producer always has weak references to the Cs, so it's easy to do it when a C is GCed. However, I noticed that the Cs usually stick around in the VM for an extended period of time before it's finally GC-ed and all this while, the data producer is producing a LOT of data it should have needed to.
Is there any way for me to force the GC of unused Cs? I am hoping for yes, but I'm expecting a No, so as a follow-up question, does anyone have a good suggestion to how I can (re)design this to make it work better/more efficiently?
Thank you!!
Some answers below make a lot of good points - in particular the suggestion to force users of C to subscribe and unsubscribe. This is difficult because:
C is just one possible implementation of an interface I (which doesn't have this subscription requirement), which is what the users really use. The C implementation is injected during run-time, so we can't force the users to comply to C-specific requirements. (Ouch?)
The components which use C can notify when they are interested and no longer interested.
When there is at least one interested component, turn on subscription. (Not before which appears the case here), when the last component un-subscribes, turn off the data.
Set<C> components = ...
public void subscribesTo(C component) {
if (components.isEmpty())
enableSubscription();
components.add(component);
}
public void unsubscribeFrom(C component) {
components.remove(component);
if (components.isEmpty())
disableSubscription();
}
I'll just go with System.gc();
There's some really interesting information in this related post: Java: How do you really force a GC using JVMTI's ForceGargabeCollection?
Apparently a lot of IDEs use that too to evaluate the amount of available heap. Guess there's no reason I can't do that too.
Perhaps we can clarify your architecture first. You have:
- A data producer (P)
- A number of consumers (C)
- A number of components that 'use' the consumers.
What I want to know is - what is the relationship from components to consumers? All you have stated is there are multiple components that use a single consumer.
Generally if the system was full of just P and Cs then you could get the C to de-register itself and you're done (As Peter shows in his example). However, in this case, a number of components use the C. I guess with limited knowledge of your architecture I would suggest that you get the components to register and de-register with each C when it needs it, and C can de-register itself from P when all components de-register.
By calling System.gc()
you suggest to the VM that it should do something about the memory situation. I quote from the javadoc:
When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.
Note that this doesn't mean that it actually has performed a GC, it just checks to see if it needs to. In practice, I haven't yet seen a VM ignore a System.gc()
call.
Normally you don't have to and shouldn't do this. The VM has a far better understanding of the behaviour of the memory subsystem than you (and I) do. But, in some cases, where the application behaviour is uncommon and you know that the memory is needed it is ok to do it.
You can't force the JVM to do garbage collection, the best you can do is suggest it via a call to System.gc()
.
Maybe a better solution would be to introduce some sort of Listener pattern with your Cs registering/deregistering with the data producer and the independent components registering with your C. As things deregister from your C it can check to see if it is no longer needed, in which case it can deregister from the data producer.
精彩评论