Java架构学习(十二)java内存结构&新生代&老年代&JVM参数调优&堆内存参数配置&解决堆栈溢出

JVM参数调优与垃圾回收机制

一、java内存结构

Java内存模型:是多线程里面的,jmm与线程可见性有关
Java内存结构:是JVM虚拟机存储空间。

Java内存结构图

这里写图片描述

Java内存机构分为:方法区、java堆、栈、本地方法栈。

方法区(永久区):就是使用static关键字修饰的基本就是存放在方法区内。
    一般来说都是存放常量信息,在类加载的时候就会被初始化。
    方法区就是全局的。所有线程都会被共享的。
    包括静态工厂创建的对象。只要被static修饰的

Java堆:创建的对象、new创建的、数组存放在堆内存。 调优策略就是调堆。
    堆所有的线程会被共享的。

栈:定义基本的局部变量、局部方法、类的方法。
   栈代码运行完毕后就会自动释放内存。
   栈是每个线程都是私有的。 互不共享,不会产生线程安全问题。

本地方法栈:主要是调用C语言的。jni

二、调优问题总结

1、在项目中,少定义static常量。否则垃圾回收机制根本就不会回收。
2、调优主要调堆。
3、尽量减少垃圾回收机制的次数,因为垃圾回收的时候线程会被卡死,当然时间很短
感受不到就是。
4、新生代回收次数尽量比老年代多。

三、垃圾回收的作用

垃圾回收机制:不定时的去回收堆内存空间的资源。

四、堆里面的 新生代与老年代

什么是堆?new 出来的对象都会存放在堆内存中。
堆内存中分配两个区:新生代、老年代。目的就是垃圾回收机制。
垃圾回收机制主要是回收新生代里面的对象。

新生代又分为:eden区、s0区、s1区。 s0区与s1区大小相等,
目的是垃圾回收机制复制算法。

新生代:刚创建对象时候先存放在新生代。
老年代:如果对象在频繁的使用,对象会放在老年代。

在jvm刚创建对象的时候会先放在eden区。

垃圾回收机制需要经常区老年代回收垃圾吗?
不需要,因为老年代都是频繁使用的对象。回收较少。

垃圾回收机制主要回收新生代。

如图:

这里写图片描述

五、堆内存参数配置

参数配置:
-XX:+PrintGC  每次触发GC的时候打印相关日志
-XX:+UseSerialGC 串行回收
-XX:+PrintGCDetails 更详细的GC日志
-Xms 堆初始值
-Xmx 堆最大可用值
-Xmn 新生代堆最大可用值
-XX:SurvivorRatio 永安里设置新生代中eden控件和from/to空间比例。
含义:-XX:SurvivorRatio=eden/from=den/to

总结:在实际工作的时候,我们可以直接将初始堆大小与最大堆大小配置相等。
这样的好处是可以减少程序运行时垃圾回收次数。从而提高效率。

代码:查看堆内存和使用内存

package com.leeue;

import java.text.DecimalFormat;

/**
 * 
 * @classDesc: 功能描述:(配置堆内存初始值大小要与堆最大内存值相等。)
 * @author:<a href="[email protected]">李月</a>
 * @Version:v1.0
 * @createTime:2018年7月31日 下午2:57:53
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        JvmInfo();
        byte[]  bytes01 = new byte[1*1024*1024];
        System.out.println("分配了1M");
        Thread.sleep(2000);
        JvmInfo();
        byte[]  bytes02 = new byte[4*1024*1024];
        System.out.println("分配了4M");
        JvmInfo();

    }
    static private String toM(long maxMemory) {
        float num = (float) maxMemory / (1024 * 1024);
        DecimalFormat df = new DecimalFormat("0.00");// 格式化小数
        String s = df.format(num);// 返回的是String类型
        return s;
    }
    public static void JvmInfo() {
        //最大内存配置信息
        long maxMemory = Runtime.getRuntime().maxMemory();
        System.out.println("最大内存配置:"+maxMemory+","+toM(maxMemory)+"M");
        //当前空闲内存
        long freeMemory = Runtime.getRuntime().freeMemory();
        System.out.println("当前空闲内存:"+freeMemory+","+toM(freeMemory)+"M");
        //已使用内存
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("已使用内存:"+totalMemory+","+toM(totalMemory)+"M");
    }
}

设置最大堆内存

-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags

这里配置了初始值是5M 最大值是20M  
设置完成后 垃圾回收机制回收了两次

设置完成后
这里写图片描述

配置新生代与老年代参数调优参数

-Xmn    新生代大小,一般设为整个堆的1/3到1/4左右
-XX:SurvivorRatio    设置新生代中eden区和from/to空间的比例关系n/1
参数: 
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

-XX:SurvivorRatio    设置新生代中eden区和from/to空间的比例关系n/1  如下图

这里写图片描述

这个参数是配置新生代与老年代的比例关系
-Xms20m -Xmx20m 
-XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2

-XX:NewRatio=2 表示新生代与老年代的关系是2:1 新生代占两份

这里写图片描述

六、JVM参数调优

1、设置初始堆大小要与最大堆大小配置相等。

这里写图片描述

2、设置新生代与老年带回收比例。
    JVM参数调优,怎么让垃圾回收机制经常区新生代进行回收?
    答:新生代与老年代比例1/3或1/4

七、解决堆内存溢出

堆溢出:
    解决方案:
    -Xms1m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError

这里写图片描述

栈溢出:产生于递归调用,循环遍历是不会出现栈溢出的。但是循环方法里
产生递归调用也会发生栈溢出

解决方案:设置线程最大调用深度
-Xss5m 设置线程最大调用深度。

Tomcat内存溢出在catalina.sh 修改JVM堆内存大小

        JAVA_OPTS="-server -Xms800m -Xmx800m
 -XX:PermSize=256m -XX:MaxPermSize=512m
 -XX:MaxNewSize=512m"

猜你喜欢

转载自blog.csdn.net/leeue/article/details/81302038
今日推荐