Java的内存组成:
Java的内存主要有两种:栈内存(stack)和堆内存(heap)
栈内存的优势是存取速度快,在栈中存放的变量都是在编译期就可确定其值、生命周期的,栈内存最大的一个特点就是数据可以共享。
堆内存的特点是可以动态分配内存,生存期也不必事先告诉编译器,由于他在运行时动态分配内存,所以存取速度较栈慢。
1、 栈内存中主要存放局部变量、基本类型、和对像的引用变量
2、 堆内存中主要存放new创建的对像和数组。
Java的内存泄露是指有被分配的对像,这种对像有两个特点:一是该对像是有引用的,二是该对像永远不会被使用,符合这两个条件的对像,即使永远不会被使用,但由于他是有引用的,GC也不会回收他,长时间的堆积就会造成内存泄露。
内存溢出的详细解决方案:
内在溢出类型:
1、 java.lang.OutOfMemoryError: PermGen space
java主要管理两种类型的内存,堆和方法,堆是给开发人员用的,方法区是JVM自己用的,用来加载类的时候,存放class的信息的,此内存不会被GC回收,如果大量的使用了第三方的Jar包或者有太多的class文件而恰好MaxPermSize设置较小,则会造成内存溢出,JVM默认此内存的大小为4M,解决方法为将将此配置配的大一点,比如:
set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m
2、 java.lang.OutOfMemoryError: Java heap space
上面一种情况只要配置得当一般不会出现,内存溢出主要是这种情况,JVM的默认内存空间(-Xms)为物理内存的1/64,最大内存(-Xmx)为物理内存的1/4。
每次GC后,当内存剩余不到40%的时候,JVM会调整内存到-Xmx的值,当内存剩余超过70%的时候,为调整内存至-Xms,所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。
注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
JVM调用GC进行垃圾回收的时机:
1、 当应该线程空闲时。
2、 当堆内存不足时
如果连续的内存回收,还是不能解决内存不足的话,就会报OutOfMemorry异常。
Java 比较占内存的原因:
引用变量是在栈中分配,当程序运行到其作用域之外的时候,该变量即被释放,相应内存也可以用作他用。
对像和数组是存放在堆内存的,即使程序运行到其作用域之外,没有引用变量引用它时,他也不会被立即释放,而是由gc在适当的时候来回收他,这也是java比较占内存的原因。
垃圾回收的基本算法:
按照基本回收策略:
1、 引用计数:持有对像的引用数,增加一个引用就增加计数,反之义然,垃圾回收时只回收引用计数为0的对像。缺点是不能处理循环引用的问题。
2、 标记-清除:第一阶段从引用根结点标记被引用的对像,第二阶段遍历整个堆,清除没有被标记的对像,缺点是需要暂停整个应用,并产生内存碎片。
3、 复制:此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处 理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两 倍内存空间。
4、 标记-整理:此算法结合了“标记-清除”和“复制”两个算法的优点。先标记,后压缩清除。
按照分区对待的方式:
1、 增量收集
2、 分代收集
按照系统线程的方式:
1、 串行收集
2、 并行收集
3、 并发收集