Does Java garbage-collection affect methods? - java

My AP Computer Science teacher tells me not to use static methods because Java garbage collection only affects non-static methods, and therefore static methods that are no longer used will take up extra memory. I'm almost positive that GC should never affect any methods, only objects, but I wanted to be sure before I say anything. So does GC have anything to do with methods?

Assuming she really said methods and not fields then your teacher is wrong on this occasion. As you say, garbage collection is the process of reclaiming memory from objects that have been allocated, the scope of the method that allocated them is irrelevant.
As a side note, static fields are a different matter. Holding objects in a static field (usually) does prevent the garbage collector doing its thing as the class will always hold a reference to it and so it won't be eligible for collection.

use static methods because Java garbage collection only affects non-static methods, and therefore static methods that are no longer used will take up extra memory.
I think you miss understood what he/she said. A method is only unloaded when its ClassLoader is unloaded, in most Java SE programs, that is never.

I think your teacher is wrong. Ask him/her whether he/she thinks that methods are also copied when objects cloned? If he/she say that yes, then he/she is really wrong.
Methods are code and code is static, i.e. it exists in one instance all the time when class exists.

Related

Are there non-static and static areas in the method area of JVM memory?

I heard that there are non-static and static areas in JVM memory in a lecture course, but I can't find any information about the two areas of the method area of JVM memory.
Do non-static and static areas exist in the method area?
I think they must be because when the program needs some non-static method, JVM has to load the method on the non-static area of the method area and it has to be efficiently deleted if the non-static method is not used anymore by heap area or stack area.
I think you might be conflating storage requirements for methods (code) and fields (data).
Non-static fields are represented in the heap node of each object that has those fields. Naturally, when the object is deleted, all of its fields go away as well.
Static fields are represented in (typically) a heap node that is associated with the class that declares the fields. Normally, this node lives for the lifetime of the JVM. However, if the associated class is unloaded, then the node is (notionally) eligible for garbage collection.
Whether the former and latter nodes are in the same area of the heap is ... implementation-dependent.
I suspect that this is what the lecture was talking about. (However, it is not entirely clear without actually seeing/hearing what the lecture material says.
Are there non-static and static areas in the method area of JVM memory?
Basically, no.
The memory that holds the code of methods is associated with the class and has the same lifetime1 as the class (see above). Therefore the code for static and non-static (instance) methods can be (and is) stored the same way.
The area in which the code is stored is also implementation-dependent. However, for recent JVMs methods are held in metaspace ... which is not strictly part of the Java heap.
A final note: you don't need to know the precise details of this unless you are or plan to be an OpenJDK developer. And if you do need (or want) to know the precise details ... look at the source code. But beware that it could take you weeks to get your head around it, depending on how experienced you are with this kind of thing.
1 - This is an oversimplification. In some contexts, the JIT compiler may recompile native code. When that happens, the JVM will reallocate the memory blocks that hold a method's native code. However, it is all taken care of ...

Reducing potential excess of garbage when using primitive types with generics?

I have this system that allows me to create and implement type-safe variables per-player. Each variable is defined along the lines of
#Foo
public static final Bar KILLS = new Bar();
The annotation marks the variable to be picked up at runtime for registration purposes. These variables are essentially static mutator methods that adjust the underlying value for the player in question like so
KILLS.set(player, 10);
The system works great however, each type (Object, int, String, etc) is backed by a mutable type which is lazily loaded into the respective player's variable map. I was curious on the potential garbage issues this design may introduce as player count scales upward. I know some things are unavoidable due to java's autoboxing mechanism but maybe there is some room for improvement elsewhere. I'm not entirely familiar with the java memory model so excuse my explanation or lack thereof.
EDIT:
To give a bit more clarity, each variable type extends a parent class and provides a type of T respectively. These children classes are then given access to override required methods which allow them to mutate the value of the concerning player variable.
Firstly, I would like to say I am a bit confused by your mention of "garbage issues", because your context is not entirely clear whether you're referring to Java's implicit garbage collection of runtime memory or whether you're concerned about this registration data is piling up somewhere else, like a database.
If you're referring to Java's runtime memory management: Java is (as you probably know) automatically garbage collected but you can suggest (with no guarantee whatsoever) Java to collect garbage at any time with System.gc(). This is almost always a micro-optimization and provides little to no real benefit as Java is already amazing at determining the correct time to do garbage collection without you. I wouldn't even bother worrying about it in Java.
If you're referring to an external model of storage of this data, I would be concerned. By having an abstract 'setter' method, for lack of better terms, you're exposing bugs or side effects to ravage that memory. That is something that needs to be dually managed to be as bug-free as possible on the Java implementation but also you need to manage the memory on the external storage yourself.
Nonetheless, a situation like this is almost certainly indicating the backing code requires restructuring and more direction. This abstract setter method is (in my opinion) a code smell.

Is there a way to receive object, without having reference to it?

Suppose following code:
Object obj = new Object();
obj = null;
At this point, i don't have any reference to this object, but it's still on the heap, because garbage collection don't happens instantly. Is there a way to re obtain reference on this object, before it'll be collected by GC?
Only possible way that i seen so far is to use Unsafe, which provides direct memory access, but i will need to know where in memory exactly object is allocated. Also, there is Weak\SoftReference, but they are implemented by special GC behavior.
P.S. To predict questions like "Why do you need it?" - Because science is not about why, it's about why not! (c)
This is highly JVM implementation specific. In a naive implementation having memory allocation information associated with each object, you could find an object whose memory has not been freed yet and it seems you are thinking into that direction.
However, sophisticated JVMs don’t work that way. Associating allocation information with each object would create a giant overhead, given that you may have millions of objects in your runtime. Not only regarding memory requirement, but also regarding the amount of work that has to be done for maintaining these information when allocating or freeing an object.
So what makes a part of your heap memory an object? Only the reference you are holding to it. The garbage collector traverses existing references and within the objects found this way, it will find meta information (i.e. a pointer to class specific information) needed to understand how much memory belongs to the object and how to interpret the contained data (to traverse the sub-references, if any). Everything unreferenced is unused per se and might contain old objects or might have never been used at all, who knows. Once all references to an object are gone, there is no information left about the former existence of this object.
Getting to the point, there is no explicit freeing action. When the garbage collector has found surviving objects, they will be copied to a dedicated new place and their old place is considered to be free, regardless of how many objects there were before and how much memory each individual object occupied when it was alive.
When you search memory that is considered to be unused, you may find reminiscences of old objects, but without references to their starting points, it’s impossible to say whether the bit pattern that looks like an object really is a dead object or just a coincidence. Even if you managed to resurrect an object that way, it had nothing to do with your original idea of being able to resurrect a reference, because the gc didn’t run yet.
Note that all modifications to this ordinary life time work by holding another reference to the object. E.g., when the class defines a non-trivial finalize() method, the JVM has to add a reference to the queue of objects needing finalization. Similarly, soft, weak and phantom references encapsulate a reference to the object in question. Also a debugger may keep a reference to an object, once it has seen it.
But for your trivial code Object obj = new Object(); obj = null;, assuming there’s no breakpoint set in-between, there will be no additional reference and hence, no way of resurrecting the object. A JVM may even elide the entire allocation when optimizing the code at runtime. So then you wouldn’t even find remainings of the object in the RAM when searching it as the object effectively never existed.
At this point, i don't have any reference to this object, but it's still on the heap, because garbage collection don't happens instantly.
It is undefined where it is, and it is also undefined whether or not garbage collection happens instantly.
Is there a way to re obtain reference on this object, before it'll be collected by GC?
You already had one and you threw it away. Just keep it.
I will need to know where in memory exactly object is allocated.
There is nothing in standard Java that will tell you that, and no useful way you could make use of the information if you could get it.
Also, there is Weak/SoftReference, but they are implemented by special GC behavior.
I don't see how this affects your question, whatever it is.

How to decide that some object should not be declared static?

My rule is that in case of primitives, I can declare them static any time I want as they will not consume much memory. In practice, I usually use static primitives as project constants.
However, I saw many programmers declare objects as static as well. Obviously static object will increase memory consumption with each new static object.
For example, I often see that sharedpreference object is declared static so that any class can have updated information from it by calling apply() from anywhere in the code. I don't use it, but I create is as instance object instead and handle the login in a different manner.
So, how shall we be sure that we can safely declare some object as static? Do we try to predict its memory consumption or there is some other better method?
The reason for the question is the project that occupied 100MB or RAM on the mobile device. Static objects were used unnecessarily so a lot of data was kept in RAM without need. Once I converted static objects to instance objects, memory consumption dropped to 60MB.
PS. I have seen horrible cases of using static objects in the app just because programmers were lazy to properly handle the logic and such apps consumed up to 100% more memory than they should.
This
Obviously static object will increase memory consumption with each new static object.
is simply wrong: a static reference won't consume more or less memory than a non-static one.
Of course the static referenced object will stay in memory, as long as the class with the reference stays in memory, which might be until the end of the JVM.
On the other hand if every instance that needs A creates and holds an instance of A that will consume much more memory than a single A for everybody.
But memory consumption is really irrelevant in 99% of the cases, so I normally only think about it when I start having problems, or it becomes obvious I will get problems if I don't consider it.
More important are criteria like the following:
Will I ever want a different instance, for example for testing.
Does really everybody all the time need the same instance?
Might I want to use inheritance
When in doubt, don't use static
Regarding the updated question, which clarified that OP is asking about memory constraint devices
It sounds like someone is using static referenced Objects on a memory constraint device as some kind of cache, i.e. in order to avoid recreation of some object.
Based on that assumption the reasoning is somewhat different the result is more or less the same:
Don't cache stuff until you know you need it
If you cache something, make sure it helps you achieving your performance goal, by actually measuring
Make sure nothing else breaks, in this case especially memory constraints
If in doubt: don't cache
Finally: If you need a cache, use a cache, not some hacked solution like an abused static reference.
You have this completely back to front. It is instance variables that will use more memory, and it is static variables that need a strong motivation for making them static. If you don't already have a good reason for making them static, thy shouldn't be.
PS. I have seen horrible cases of using static objects in the app just because programmers were lazy to properly handle the logic and such apps consumed up to 100% more memory than they should.
Complete and utter nonsense. You have never seen any such thing. Using static variables doesn't double the memory, unless the class is never instantiated at all.

In java, is it possible to find the current objects on the memory heap at any particular point of time during execution?

Say I have classes
class A{
//code for class A
}
class B{
//code for class B
}
class A{
public static void main(String a[]){
//Initialize m instances of A and n instances of B and store each in arrays
//Equate any arbit index in the array to null
}
}
In this scenario, my main goal is to find all active instances of classes A and B in the memory at any point.
I suppose it must be possible using a debugger.
However, due to some reason (the reason being beyond the scope of the question), I am required to get the instances from within the code itself. Thus, i need a function like
public void getAllActiveInstances(){
//Print values
}
Edit: I don't need instances to operate over them. I just need to know whether they exist or not. This is mainly for debugging purposes.
If this is not possible then kindly explain how to do the same using debuggers.
The short answer is no, you should not be looking inside of memory at any time with java.
The long answer is, if there was any way of accessing an object after GC has collected it, then you are violating the GC's principal of only collecting things that cannot be reached in any way by the executing code. Garbage collected memory is freed and returned to the program to do anything it wants with it. This means if you've GC'd an object A, java is allowed to write any number of things into that location, destroying the "A-ness" of that block of memory. Attempting to read an object B that is now stored in that memory block and pretending it's an A will cause all sorts of problems.
Going forward: To keep track of all the classes you've created, I would suggest modifying the class itself. Your class can have a static container (like a HashMap), and the constructor adds the constructed class to the HashMap. However, note that because you are hanging onto references to all of your created object, Garbage collect will never collect those objects and free up that memory.
"In this scenario, my main goal is to find all active instances of classes A and B in the memory at any point irrespective of the Garbage Collector having deleted the object or not."
If the garbage collector has deleted it, it won't be an active instance, or indeed any kind of instance.
There is no Java API for this, sure JRockit Flight Control and/or a debugger could do this for you, but if you want an actual programmatic way of doing it, you'll have to hand-roll it. Good luck with making that reliable. You'll probably need to use Constructors and Finalizers to increase and decrease your object count.
Don't try and implement your own object pools unless you really, really think you can beat the hotspot optimiser at its own game.
As you mentioned you can do it using debugger. Java provides debugging API. You can kind of implement your own debugger and connect to the application itself.
Other way is to instrument your classes. I know the following techniques:
Instantiate them using special factory that stores references to all instances that have to be monitored.
Use AOP (e.g. AspectJ). The aspect will register created instances into repository (as described above)
Use java instrumentation package to change class on the fly. Take a look on SizeOf - a very simple project that uses java instrumentation API. You can use it as an example to learn the issue.

Categories