1、参数设置
默认的java虚拟机的大小比较小,在对大数据进行处理时java就会报错:java.lang.OutOfMemoryError。
a、参数解释:
-Xmx
Java Heap(堆)最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
-Xms
Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
-Xmn
Java Heap Young区(年轻代)大小;
-Xss
每个线程的Stack大小;
-XX:PermSize
JVM初始分配的非堆内存大小,默认是物理内存的1/64。
-XX:MaxPermSize
JVM最大分配的非堆内存大小,默认是物理内存的1/4。
-XX:NewSize
JVM初始分配的新生代堆区域内存大小。
-XX:MaxNewSize
JVM最大分配的新生代堆区域内存大小。
-XX:ReservedCodeCacheSize
编译代码时的缓存空间大小。
b、如何设置JVM的内存分配:
(1)当在命令提示符下启动并使用JVM时(只对当前运行的类生效):
java -Xmx128m -Xms64m -Xmn32m -Xss16m 类名
(2)当在集成开发环境下(如eclipse)启动并使用JVM时:
● 打开eclipse-窗口(window)-首选项-Java-已安装的JRE(对在当前开发环境中运行的java程序皆生效)编辑当前使用的JRE,在缺省VM参数中输入:
-Xmx128m -Xms64m -Xmn32m -Xss16m
● 打开eclipse-运行-运行-Java应用程序(只对所设置的java类生效)选定需设置内存分配的类-自变量,在VM自变量中输入:-Xmx128m -Xms64m -Xmn32m -Xss16m
注:如果在同一开发环境中同时进行了以上两个设置,则第一个设置生效,第二个设置无效。
(3)当在服务器环境下(如Tomcat)启动并使用JVM时(对当前服务器环境下所以Java程序生效):
a. 设置环境变量:
变量名:CATALINA_OPTS
变量值:-Xmx128m -Xms64m -Xmn32m -Xss16m
b. 打开Tomcat根目录下的bin文件夹,编辑catalina.bat,在set JAVA_OPTS=%JAVA_OPTS%….这句之后加上:set JAVA_OPTS=%JAVA_OPTS% -Xms1024m -Xmx1024m
c、若没有catalina.bat,只有tomcat.exe,tomcat6w.exe;则可以在启动tomcat6w.exe 后 右键配置–Java–java option 下面输入:
-Xmx256m
-Xms64m
重起tomcat服务,设置生效
2、简述jvm
JVM就是我们常说的java虚拟机,它是整个java实现跨平台的 最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可 以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解 释给本地系统执行。JVM 是 Java 平台的基础,和实际的机器一样,它也有自己的指令集,并且在运行 时操作不同的内存区域。 JVM 通过抽象操作系统和 CPU 结构,提供了一种与平台无关的代码执行方法,即与特殊的实现方 法、主机硬件、主机操作系统无关。但是在一些小的方面, JVM 的实现也是互不相同的,比如垃圾回收 算法,线程调度算法(可能不同 OS 有不同的实现)。 JVM 的主要工作是解释自己的指令集(即字节码)到 CPU 的指令集或 OS 的系统调用,保护用户免被恶意程序骚扰。 JVM 对上层的 Java 源文件是不关心的,它关注的只是由源文件生成的类文件( class file )。类文件的 组成包括 JVM 指令集,符号表以及一些补助信息。
3、垃圾回收机制(年轻代,老年代,永久代)
回收哪些内存?
程序计数器,虚拟机栈,本地方法栈随线程生,随线程灭。
栈帧随方法进入和退出,执行进栈,出栈操作。内存可知。这几个区域的内存分配和回收具有确定性,方法结束或线程结束时直接回收内存。
java堆和方法区的内存分配和回收是动态的,垃圾收集器所关注的是这部分内存。
如何判定对象已死?
1 引用计数算法:
最简单的方法,就是给对象添加一个引用计数器,当有一个地方引用他,计数器值就加1,引用失效就减1;任何时刻计数器都为0的对象就是不可能再被使用的。但是由于无法解决对象之间相互循环引用的问题,java不使用这种方法管理内存。
2根搜索算法(可达性分析算法)
java采用。通过一系列名为“GC root”的对象作为起点,从这些点开始向下搜索,搜索走过的路劲叫做引用链。当一个对象到GC root没有任何引用链时,则证明此对象是不可用的。
Gc ROOT:
如何回收对象?
分为年轻代,老年代,永久代。
永久代:
就是指方法区要回收的内存:主要有废弃常量和无用的类两部分内容。判定一个类是否是“无用的类”需满足三个条件:
1 该类所有的实例都已近被回收,java堆不存在该类的任何实例。
2 加载该类的classLoader已经被回收
3 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
新生代:
新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。采用复制算法回收。
复制算法是把整个堆分成两个半区(From,To), GC的过程其实就是把存活对象从一个半区From拷贝到另外一个半区To的过程,而在下一次回收时,两个半区再互换角色。在移动结束后,再更新对象的指针引用。节点拷贝算法由于在拷贝过程中,就可以进行内存整理,所以不会再有内存碎片的问题,同时也不需要再专门做一次内存压缩。,而它最大的缺点在于需要双倍的空间
老年代:
如果新生代在若干次清理(可以进行设置)中依然存活,则移入老年代,有的内存占用比较大的直接进入老年代。老年代使用标记清理算法,清理的频率比较低。
标记清理算法:对所有存活对象进行一次全局遍历来确定哪些对象可以回收,遍历的过程从根出发,找到所有可达对象,除此之外,其它不可达的对象就是垃圾对象,可被回收。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。
相比较引用计数算法,标记-清除算法可以非常自然的处理环形引用问题,另外在创建对象和销毁对象时时少了操作引用计数值的开销。
它的缺点在于标记-清除算法是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止。另外,标记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,在清除阶段,清除垃圾对象后会造成大量的内存碎片。
4、内存分配
蓝色框:所有线程共享的数据区
白色框:线程隔离的数据区(即独立线程数据区)
java虚拟机栈
Java虚拟机栈是线程私有的,它的生命周期与线程相同,每个线程创建的同时都会创建Java虚拟机栈。虚拟机栈描述的是java方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用 直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。局部变量表存放了编译期可知的各种基本数据类型(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、对象引用类型。,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址,因此Java中基本类型的变量是值传递,而非基本类型的变量是引用传递,Sun JDK的实现中JVM栈的空间是在物理内存上分配的,而不是从堆上分配。
由于JVM栈是线程私有的,因此其在内存分配上非常高效,并且当线程运行完毕后,这些内存也就被自动回收。
当JVM栈的空间不足时,会抛出StackOverflowError的错误,在Sun JDK中可以通过-Xss来指定栈的大小
操作数栈,想必学过数据结构中的栈的朋友想必对表达式求值问题不会陌生,栈最典型的一个应用就是用来对表达式求值。想想一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。
指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。
方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。
5、垃圾回收器
http://blog.csdn.net/chenleixing/article/details/45190225
6、jvm调优
http://www.360doc.com/content/12/0113/08/1073512_179088229.shtml