0

I'm trying to understand why the JVM decides to load certain classes when it doesn't appear it needs to. Consider the following example code:

public class Foo {
    public void foo() {
    }

    static class Bar {
    }

    public Bar bar() {
        return new Bar();
    }
}

When calling new Foo().foo(), Bar is not loaded by the classloader since it's not needed. But, if we change the example to have bar return an instance of a sub-class:

public class Foo {    
    public void foo() {
    }

    static class Bar {
    }

    static class BigBar extends Bar {
    }

    public Bar bar() {
        return new BigBar();
    }
}

Calling new Foo().foo() causes the classloader to load both the Bar and BigBar classes even though neither of them are needed. Why?

Aside from this specific scenario, is there a way to learn why the JVM decides it needs to load a class, in general?

Josh Stone
  • 4,328
  • 7
  • 29
  • 37
  • Your question is cryptic. If you have JDK8, JDK8 will be used. You cannot have 2 JDK's being used at the same time. – Rishi Goel Sep 16 '16 at 05:42
  • Have you compiled the code with `-target 1.7` and tested how it runs on a 7 version JRE? That would be a way more straight-forward way to see how it handles, not by guessing what the classloader is doing. – Kayaman Sep 16 '16 at 05:45
  • 1
    @JoshStone Which code? Which classes? "Some code tries to load some classes from Java 8" doesn't give much to work with. – Kayaman Sep 16 '16 at 05:48
  • I have a class with some methods that return CompletableFuture (a JDK 8 class). From what I understand of Java classloading, CompletableFuture should not be loaded until I actually call a method that returns it. I am not calling such a method, but it's still getting loaded. – Josh Stone Sep 16 '16 at 05:50
  • @JoshStone You mean that when you call a method, the JVM will check the return type of that method and if it's a class it hasn't loaded yet it will start loading the class at *that* point? – Kayaman Sep 16 '16 at 06:14
  • @JoshStone Well show an example. Generally speaking you're approaching this the wrong way. If you're creating a program in version `N` that is supposed to work for versions `< N`, you're not supposed to use all the new fancy classes (and some mechanisms) introduced in version `N`. You can get around that a bit with dynamic class loading and plugin functionality, but not with any `if(version == 7) callJava7Version(); else callJava8Version();` style things (an over the top example). – Kayaman Sep 16 '16 at 06:17
  • @JoshStone As for tracking the actual classloading, see [this answer](http://stackoverflow.com/questions/9921081/how-to-track-when-class-is-loaded-and-destroyed-in-jvm). – Kayaman Sep 16 '16 at 06:27
  • @Kayaman -XX:+TraceClassLoading only shows after a class was loaded. It doesn't allow you to see why the JVM is attempting to load a class. – Josh Stone Sep 16 '16 at 06:34
  • @JoshStone Yeah, and it still gives more information than what you've given in this question. The JVM is trying to load a class because it needs it, i.e. it's being referenced from somewhere. If you're not going to show any code, then we can't even begin to guess why it needs it. – Kayaman Sep 16 '16 at 06:38
  • @JoshStone You're saying that the class isn't loaded even though it's the return type of the method? I remember answering your questions previously. You give 0 information, and instead of providing actual data, you refer to some irrelevant resources. Do you want help or not? If yes, provide relevant pieces of the actual code. You can anonymize it, as long as it doesn't lose relevant information. Otherwise this is just an exercise in futility. – Kayaman Sep 16 '16 at 06:50
  • @Kayaman I'm not sure what you mean - I just linked to actual code where this is occurring. The question is, why does it occur there and why does changing that line resolve the issue? – Josh Stone Sep 16 '16 at 06:55
  • @JoshStone So that's the actual code you're working on? I'm sorry, I thought it was some other code that wasn't related. – Kayaman Sep 16 '16 at 07:02
  • @Kayaman I'm a user of that library and hit this issue there. Now that you can see the problem, what's the cause? – Josh Stone Sep 16 '16 at 07:04
  • 1
    @JoshStone I'm surprised that `CompletableFuture` wouldn't be loaded at that point, but at least in this case it's easily explained that when you have `null` there, the type becomes irrelevant. It's not a "`(CompletableFuture)null`", it's just plain null, and the class information is not needed for anything. – Kayaman Sep 16 '16 at 07:05
  • @Kayaman The class info is never needed since I'm not even calling that method. – Josh Stone Sep 16 '16 at 07:07
  • @JoshStone Well, if I were you I'd observe the class loading patterns. It'll tell you what was loaded, when, and after what other classes. – Kayaman Sep 16 '16 at 07:13
  • Updated the original post with a simple example that demonstrates the scenario I'm seeing. – Josh Stone Sep 16 '16 at 07:40

2 Answers2

1

Here is a good read from Internals of Java Class Loading

Whenever a new JVM is started by typing java MyMainClass, the "bootstrap class loader" is responsible for loading key Java classes like java.lang.Object and other runtime code into memory first. The runtime classes are packaged inside of the JRE\lib\rt.jar file. We cannot find the details of the bootstrap class loader in the Java documentation, since this is a native implementation. For the same reason, the behavior of the bootstrap class loader will also differ across JVMs.

In a related note, we will get null if we try to get the class loader of a core Java runtime class, like this:

log(java.lang.String.class.getClassLoader());

Next comes the Java extension class loader. We can store extension libraries, those that provide features that go beyond the core Java runtime code, in the path given by the java.ext.dirs property. The ExtClassLoader is responsible for loading all .jar files kept in the java.ext.dirs path. A developer can add his or her own application .jar files or whatever libraries he or she might need to add to the classpath to this extension directory so that they will be loaded by the extension class loader.

The third and most important class loader from the developer perspective is the AppClassLoader. The application class loader is responsible for loading all of the classes kept in the path corresponding to the java.class.path system property.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • I'm familiar with classloading in general. What I need to learn is what is triggering a class to be loaded in this exact scenario, because it's not obvious. – Josh Stone Sep 16 '16 at 05:48
0

well explained http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html

When Class is loaded in Java Class loading is done by ClassLoaders in Java which can be implemented to eagerly load a class as soon as another class references it or lazy load the class until a need of class initialization occurs. If Class is loaded before its actually being used it can sit inside before being initialized. I believe this may vary from JVM to JVM. While its guaranteed by JLS that a class will be loaded when there is a need of static initialization. When a Class is initialized in Java 1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.

2) an static method of Class is invoked. 3) an static field of Class is assigned. 4) an static field of class is used which is not a constant variable. 5) if Class is a top level class and an assert statement lexically nested within class is executed.

  • Did you read the question? The class is being loaded before it is referenced or used. According to the link you posted, the class should not be loaded. – Josh Stone Sep 16 '16 at 16:34