01_JVM问题汇总
1. 静态成员变量到底是放在方法区,还是堆中?
答: Java虚拟机规范没有规定方法区的实现细节,不同的虚拟机实现的方式不同。对于常见的HotSpot虚拟机而言,在JDK1.7之前,静态成员变量存放在方法区,而在JDK1.7以及之后的版本中,静态成员变量存放在堆中,
2. 方法区存放了什么东西?
答: 类的方法代码,变量名,方法名,访问权限,返回值等等。
3. 类加载器是按需加载,我现在就想一次性加载所有的类,可不可以?
答: 可以啊,虽然默认的类加载机制,只能让你在运行代码的过程中,遇到什么类加载什么类,但是你可以自己自定义类加载器啊。
4. 什么是实例变量?
答: 类的属性就是实例变量,它处于类的内部,但是在类的成员方法之外定义的。
5. 一个类经过初始化阶段之后,是不是就产生实例对象了?
答: 不是!类的初始化阶段,仅仅只是初始化类而已,与实例对象没有任何关系。当且仅当用new关键字才能创建一个实例对象!
比如我们在代码中使用ServiceA.class,这个时候就会加载并初始化ServiceA这个类,但是我们没有创建这个类的实例对象,所以不会初始化它的实例变量。
6. 什么是动态部署,什么是静态部署呢?
动态部署: 不停止Tomcat进程,直接把代码扔到Tomcat目录下,自动加载最新的代码,也就是热部署。
静态部署: 先停止Tomcat进程,接着把代码扔到Tomcat目录下,然后重启Tomcat加载代码。
7. 方法区会不会进行垃圾回收?
答:满足以下条件,就会进行垃圾回收:
1.该类的所有实例对象,在堆内存中,都已经被JVM回收了。
2.这个类的ClassLoader已经被回收了(这个条件是比较苛刻的,因为ClassLoader是大家共用的,单例的)。
3.没有任何一个人引用这个类的Class对象。
8. 方法对应的栈帧出栈后,局部变量需要垃圾回收吗?
答: 不需要。首先,JVM的垃圾回收指的是对新生代、老年代、方法区,这三块区域进行垃圾回收,没有针对方法的栈帧。其次,方法结束后,栈帧出栈,栈帧中存放的局部变量就直接从内存里面清理掉了。
9. 如果短时间内创建了大量的大对象,直接进入老年代,岂不是会导致频繁的full gc?
答: 按照"-XX:PretenureSizeThreshold"的配置来说,的确如此。但是我们在代码中就不应该频繁的创建大对象,如果业务有需求,那就分情况讨论。
如果大对象是短生命周期对象,那就适当的把PretenureSizeThreshold的值调大,让大对象保持在新生代中,虽然每次Minor GC后,大对象的确会导致存活对象的复制时间变长,但毕竟是短生命周期,所以做不了几次Minor GC,这些大对象也就被回收了。
如果大对象是长生命周期对象,那就可以把PretenureSizeThreshold适当调小,或者不调整,让大对象直接进入老年代,为新生代腾出空间。如果无法对内存扩容,可以调小-Xmn,给老年代更大的内存。