jvmjvmjvm

一、jvm内存结构

面经 | 我是如何通过校招拿到京东的Offer的。-HollisChuang's Blog

二、类加载器 

  • 启动类加载器:又称为引导类加载器,由C++编写,无法通过程序得到。主要负责加载JAVA中的一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar中。
  • 扩展类加载器:主要加载JAVA中的一些拓展类,位于<JAVA_HOME>/lib/ext中。
  • 应用程序类加载器:又称为系统类加载器,主要用于加载CLASSPATH路径下我们自己写的类。

双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层次的类加载器都是这样的,所以所有加载请求最终都会传送到启动类加载器中,只有当父加载器无法加载时,子加载器才会尝试自己去加载。

三、立即对类进行初始化的情况

 1). 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时:注意,newarray指令触发的只是数组类型本身的初始化,而不会导致其相关类型的初始化,比如,new String[]只会直接触发String[]类的初始化,也就是触发对类[Ljava.lang.String的初始化,而直接不会触发String类的初始化时,如果类没有进行过初始化,则需要先对其进行初始化。生成这四条指令的最常见的Java代码场景是:

  • 使用new关键字实例化对象的时候;
  • 读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候;
  • 调用一个类的静态方法的时候。

 2). 对类进行反射调用时:使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

 3). 初始化子类时:当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

 4). 虚拟机启动时:当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

 5). 当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。

四、类的生命周期

加载--验证--准备--解析--初始化--使用--卸载。

1、 加载(Loading):通过类加载器读取类的字节码文件,并将其转换成内部数据结构,以便在JVM中使用。

  (1). 通过一个类的全限定名来获取定义此类的二进制字节流(并没有指明要从一个Class文件中获取,可以从其他渠道,譬如:网络、动态生成、数据库等);

  (2). 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;

  (3). 在内存中(对于HotSpot虚拟就而言就是方法区)生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;

2、 验证(Verification):对类的字节码进行验证,确保符合Java虚拟机规范及安全规则。

验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

3、准备(Preparation):为类的静态变量分配内存,并设置默认值(零值)。

准备阶段是正式为类变量(static 成员变量)分配内存并设置类变量初始值(零值)的阶段,这些变量所使用的内存都将在方法区中进行分配。

4、解析(Resolution):将类的符号引用替换为直接引用,以便在运行期间可以直接访问到所有的类、方法、字段等。

5、初始化(Initialization):执行类的静态初始化代码块,报考静态变量的初始化和静态初始化块的执行。

6、使用阶段:类被使用时,JVM会根据需要加载该类的其他部分,并执行其方法。

7、卸载阶段:当类不再被使用时,JVM负责卸载该类,释放其占用的内存。

五、静态变量导致内存泄漏

apache的poi导出,导出Excel的工具类中,将workBook和一些字体、样式类定义成工具类的静态变量,导致内存泄漏。

原因:静态变量存在方法区中,与堆中的对象存在引用关系,导致这些无用的对象一直在堆中不会被回收,进而造成内存泄漏。

解决方案:将静态变量封装至内部类中,每次导出new一个该内部类的对象,用完就会被回收。

六、JVM常用命令

jmap -histo:live 25085 | head -20 查看进程中占用资源最大的前20个对象

jinfo:可以输出并修改运行时的java 进程的opts。 
jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。 
jstat:一个极强的监视VM内存工具。可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量。 
jmap:打印出某个java进程(使用pid)内存内的所有'对象'的情况(如:产生那些对象,及其数量)。 
jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。

JVM常用参数

-Xms:指定最小堆大小。-Xmx:指定最大堆大小。

-Xmn:设置新生代的内存空间大小。-Xss:每个线程的堆栈大小(方法栈大小)。

-XX:NewRatio: 老年代(不包含永久区):新生代(eden + 2*s)。例如4,即新生代:老年代 = 1:4,即年轻代占堆的1/5

-XX:SurvivorRatio:新生代中Eden:Survivor容量比值,默认值为8,即两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值