您好,欢迎访问三七文档
当前位置:首页 > 办公文档 > 理论文章 > JVM学习笔记,大量例子,保证学会
目录什么是Java虚拟机?......................................................................................................1虚拟机的生命周期?.........................................................................................................1程序计数器是什么?.......................................................................................................2什么是Java虚拟机栈?..................................................................................................2什么是栈深度?...............................................................................................................2Java虚拟机栈GC内存测试............................................................................................8Java堆内存调优.............................................................................................................17持久代的设置.................................................................................................................23线程栈的设置.................................................................................................................25JVM垃圾回收器及测试.................................................................................................28性能调优.........................................................................................................................35Tomcat调优实践...........................................................................................................40网络摘抄:........................................................................................................................45什么是Java虚拟机?Java虚拟机就是就是运行java程序的一个实例,就和电脑的虚拟机一样有自己的内存空间,CUP等,一个运行时的java虚拟机实例的天职就是负责运行一个java程序,在启动一个java程序的同时也就会诞生一个虚拟机的实例,当java程序退出,虚拟机的实例就随之消亡,比如说,如果在同一台电脑上面同时运行了3个java程序,就会得到3个java虚拟机的实例,每个java程序都运行在它自己的虚拟机中。Java虚拟机内部有2个线程,守护线程和非守护线程。守护线程通常是由java虚拟机内部使用,如执行垃圾收集任务的gc,而java的初始线程为非守护线程(main方法)。虚拟机的生命周期?当非守护线程终止后,虚拟机的实例就自动退出了,也能通过System.exit方法退出。Java虚拟机的内存模型:1.程序计数器2.Java虚拟机栈3.本地方法区4.Java堆5.方法区程序计数器是什么?程序计数器是一块很小内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。字节码解释工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理等基础功能都由计数器所完成。也就是说程序计数器就是负责程序执行字节码指令的。什么是Java虚拟机栈?java虚拟机栈也是线程私有的内存空间,它和java线程在同一时间创建,它保存方法的局部变量、部分结果,并参与方法的调用和返回。每一个方法被调用直至完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。java虚拟机规范中,定义了两种异常与栈空间相关:StackOverflowError及OutOfMemoryError.使用-Xss参数来设置栈的大小,栈的大小直接决定了函数调用可以达的深度由于栈中包括局部变量表,操作数栈,返回地址等信息,方法在调用时,如果方法的参数和局部变量相对较多,那么栈中的局部变量表就越大,它的栈帧就越大。栈深度者越浅。什么是栈深度?我们的很多变量都是存放在栈内存中的,栈的高度称之为栈深度,栈深度越高,深度就越深,所存放的局部变量就越多,如果栈的深度不够深,局部变量越多,就容易出现异常StackOverflowError栈溢出异常及OutOfMemoryError(更多出现在堆内存溢出情况),如下图测试结果:如果栈深度不够出现了StackOverflowError,这时候就需要通过设置-Xss进行设置栈的大小,栈的大小直接决定了函数调用可以达的深度。由于栈中包括局部变量表,操作数栈,返回地址等信息,方法在调用时,如果方法的参数和局部变量相对较多,那么栈中的局部变量表就越大,它的栈帧就越大。栈深度者越浅。下图测试代码多了6个局部变量,查看栈深度。测试多了变量栈的深度也随之下降了。程序设计:尽量少使用局部变量,局部变量过多会造成栈深度变浅,导致栈溢出。栈设置,并不是设置的越大越好,应该根据项目的实际情况进行设置。栈中的局部变量表就越大,它的栈帧就越大。栈深度者越浅。如何查看栈中的变量表呢?jclasslib工具可以查看class文件中每个方法所分配的最大局部变量表容量等。局部变量表是以字为单位,进行内存的划分,long和double占2个字,另外每一个虚拟机都会有一个This执行变量,占1一个字。测试:使用jclasslib工具查看:由上图看出,显示我们的栈深度为7,字节为13long占两个字节,有6个Long类型占6*2个字+1个字(This)=13个字Java虚拟机栈GC内存测试测试程序:s查看字:为什么test1只有3个字呢?作用域不同,即在定义b的时候a的作用域已经没有意义了,那么b就可以完全重用a变量的空间。单定义到大括号作用域内,字还是存在的,只不过没有被重用。b重用是因为在运行的过程中a作用域的字被gc掉了。测试一查看GC:可以看出,我们分配了一个较大的空间,gc过后,好像并没有怎么回收。测试二查看GC可以看到,通过用a重用b的空间,gc过后,内存已经被回收了测试三被GC,内存回收掉了测试四程序查看GC没有被GC测试五:没有被gc,只是a把c的空间重用了,并没有重用b的空间测试六:已经GC,两个变量被重用测试七:方法调用过后,可以通过gc被gc掉。总结局部表里中的字,在方法没有结束之前(除非被强制设置为null或者被其他的变量复盖空间)是不能GC,但是一旦方法结束过后,那么是可以被gc掉的Java堆内存调优什么是Java堆内存?Java堆是Java运行时内存最重要的部分,几乎所有的对象和数组都是在堆中进行分配空间。Java堆可以分为新生代和老年代两个部分,新生代用于存放刚刚产生的对象和年轻对象,如果对象经过几次minorGC,都没有被GC掉,生存时间足够长,新生代就会被移入到老年代中。新生代:包括3块区域:Eden区,Survivor0空间和Survivor1空间老年代只有一个区,老年代是存放时间较长,经过垃圾回收次数较多的对象。理想情况下,老年代都是放一些声明周期很长的对象,数量应该是很少的。比如数据库连接池。堆空间如下图:堆内存的GC:当程序在堆内存中运行的时候,会出现两种GC,minorGC,FullGCminorGC(小范围的GC)是经常会发生的事情,发生在年轻代,FULLGC全局GC,内存不够用触发会造成延时。并发量过大有可能出现在JVM上面。堆内存空间的存储。每一次放对象的时候,都是放入eden区域,和其中一个survivor区域;另外一个survivor区域是空闲的。当eden区域和一个survivor区域放满了以后(spark运行过程中,产生的对象实在太多了),就会触发minorgc,小型垃圾回收。把不再使用的对象,从内存中清空,给后面新创建的对象腾出来点儿地方。清理掉了不再使用的对象之后,那么也会将存活下来的对象(还要继续使用的),放入之前空闲的那一个survivor区域中。这里可能会出现一个问题。默认eden、survior1和survivor2的内存占比是8:1:1。问题是,如果存活下来的对象是1.5,一个survivor区域放不下。此时就可能通过JVM的担保机制(不同JVM版本可能对应的行为),将多余的对象,直接放入老年代了。如果你的JVM内存不够大的话,可能导致频繁的年轻代内存满溢,频繁的进行minorgc。频繁的minorgc会导致短时间内,有些存活的对象,多次垃圾回收都没有回收掉。会导致这种短声明周期(其实不一定是要长期使用的)对象,年龄过大,垃圾回收次数太多还没有回收到,跑到老年代。老年代中,可能会因为内存不足,囤积一大堆,短生命周期的,本来应该在年轻代中的,可能马上就要被回收掉的对象。此时,可能导致老年代频繁满溢。频繁进行fullgc(全局/全面垃圾回收)。fullgc就会去回收老年代中的对象。fullgc由于这个算法的设计,是针对的是,老年代中的对象数量很少,满溢进行fullgc的频率应该很少,因此采取了不太复杂,但是耗费性能和时间的垃圾回收算法。fullgc很慢。fullgc/minorgc,无论是快,还是慢,都会导致jvm的工作线程停止工作,stoptheworld。简而言之,就是说,gc的时候,导致延时,停止工作。一直等着垃圾回收结束。这个时候,问题就来了:1.频繁的minorGC,也会导致程序的延时,停止工作,影响性能2.老年代囤积大量的活跃对象(短生命周期额对象),导致频繁发生Fullgc,FulleGC时间比minorGC时间长,可能导致程序长时间的停止工作。严重影响程序的运行速度和性能。测试:如何设置最大堆内存?java应用程序可以使用的最大堆可以用-Xmx参数指定,最大堆指的是新生代和老年代的大小之和的最大值。测试:最小堆内存的设置:1.为什么设置和最大的堆内存还要设置最小的堆内存呢?java程序在运行时首先会被分配-Xms指定的内存大小,并尽可能尝试在这个空间段内运行程序,确实无法满足时才会向操作系统申请更多的内存,直到内存大小达到-Xmx指定的最大内存为止,如果超过-Xmx的值,则抛出OutOfMemoryError比如:你设置的最小堆内存为10M,那么程序会最先在你最小的堆内存中运行,如果确实无法满足了才会申请内存,直到XMX。超过报错。2.如何设置最小堆内存?java应用程序可以使用的最小堆可以用-Xms参数指定,也就是JVM启动时,所占据的操作系
本文标题:JVM学习笔记,大量例子,保证学会
链接地址:https://www.777doc.com/doc-4464469 .html