JVM内存分配

内存分配其实真正来讲是有三种的、但对于JVM来说只有两种

  • 栈内存分配:

大家在调优的过程中会发现有个参数是-Xss 默认是1m,这个内存是栈内存分配, 在工作中会发现栈OutOfMemory Error内存溢出、就是因为它的内存空间不够了 一般情况下没有那么大的栈、除非你的一个方法里边有几十万行代码、一直往那压、不出,所以导致栈的溢出、栈的内存分配直接决定了你的线程数 、比如说你默认情况下是1m 、系统一共给你512m、那最高可以分配512个线程,再多系统分配不了啦、因为没有那么多的内存 、像tomcat、resin、jboss等、有个最大线程数、要根据这个来调、调个100万没有意义、分配不了那么大、调太少整个性能发挥不出来 ,调这个 、跟你的cpu有关系、需要找一个折中位置 、根据应用 、是IO密集型的还是CPU密集型的来调-Xss的值、它这里边主要保存了一些参数 、还有局部变量 、就比如说写代码、有开始有结束、这里边肯定定义了很多变量、比如:int x=1 y=0 只要在这方法内的都属于局部变量 、因为你要做运算、要把这东西存住、只有等程序结束的时候才能销毁,对于这种参数是不会产生线程安全问题、因为线程是私有的

  • 堆内存分配:

Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢

jvm堆结构

                     (图一)

1.Young(年轻代)

年轻代分三个区。一个Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区(Old。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。

2.Old(年老代)

年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。

3.Permanent:(持久代)

也叫方法区、用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。

举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。

通常我们说的JVM内存回收总是在指堆内存回收,确实只有堆中的内容是动态申请分配的,所以以上对象的年轻代和年老代都是指的JVM的Heap空间,而持久代则是值指MethodArea,不属于Heap。

java堆结构和垃圾回收

                    图(二)

Direct Momery 严格意义来说也算堆,它是一块物理内存、可以分为操作系统内存、是比较快的、不会走JVM 在java里边实现了内存映射、这样速度更快
CodeCache 放一些字节码、类的信息会放在里边
Permanent Generation space 方法区、严格意义来说也属于堆
Eden Space 区
Survivor Space区
Tenured Generation Old区(年老代)

JVM GC 管理
调优大部分调优的是怎么回收,Minor GC 回收Eden Space和 Survivor Space , Full GC回收所有区域
不管什么GC,回收过程中会出现暂停、回收过程中用户线程是不会工作的、这样就造成程序卡了 这是无法改变不了的事实、避免不了、不过可以优化暂停时间的长短
原则上不能出现Full GC 、所有区域都要跑一遍 、出现Full GC 应用就不可用

Jvm 堆配置参数

1、-Xms初始堆大小
默认物理内存的64/1(<1GB),建议小于1G、可根据应用业务调节

2、-Xmx最大堆大小
默认物理内存的4/1(<1GB)、建议小于1G、实际中建议不大于4GB(否则会出现很多问题)

3、一般建议设置 -Xms= -Xmx
好处是避免每次在gc后、调整堆的大小、减少系统内存分配开销

4、整个堆大小=年轻代大小+年老代大小+持久代大小(Permanent Generation space区、也会被Full GC回收)

jvm新生代(young generation

图(三)

1、新生代=1个eden区和2个Survivor区
2、-Xmn 年轻代大小
设置年轻代大小、比如-Xmn=100m那么新生代就是100m,然后共享
3、-XX:NewRatio
年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
4、-XX:SurvivorRatio
Eden区与Survivor区的大小比值,设置为8(默认是8) ,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
比如新生代=100m,设置-XX:SurvivorRatio为8,那E =80m S0 =10m S1=10m(1/10)
5、用来存放JVM刚分配的Java对象

java老年代(tenured generation)

           图(四)

1、老年代=整个堆-年轻代大小-持久代大小
年轻代就是上面讲的-xmn配置的参数、持久代参数默认是0
2、年轻代中经过垃圾回收没有回收掉的对象被复制到年老代。
就是这个对象收集完一次、发现被引用了、某个地方使用了、回收不掉才放进去,一般是多次回收、从E区回收过程中、先进S0或者S1、S0或者S1再回收一次、回收不掉再放到年老区
3、老年代存储对象比年轻代年龄大的多,而且不乏大对象。
对互联网企业来说、最常用的是"缓存"的对象比较多、缓存一般会用弱引用、但弱引用也不会轻易被回收的、除非是在整个堆的内存不够的情况下、防止你的内存宕机、强引用是和垃圾回收机制相关的。一般的,如果一个对象可以通过一系列的强引用引用到,那么就 说明它是不会被垃圾回收机制(Garbage Collection)回收的,
刚才说了缓存对象一般是弱引用、有些数据丢了是没关系的、只是提高你的系统性能才放到缓存里边去、但是如果有一天内存不够了 、缓存占了很大一部分对象、你不回收的话、你整个系统都不可用了、整个服务都不能用了、如果回收掉、我可以从数据库去取、可 能速 度慢点、但是我的服务可用性不会降低
比如说刚开始分配的对象 、这个对象暂定是OLD区、刚开始一部分内存区域被缓存占据了、一般情况下对于一个缓存的设计都有初始值、对于java来说、比较通用的缓存是可以自动伸缩的、
如图(四)整个OLD区50M有45M是被缓存占据了、不会被回收掉、那整个OLD区只有5M可以用了 、假如E区有40M 、S0 分配10M 、S1分配也是10M 、理想情况下、经过E区到S0、S1到老年代的大小不到1M、 那5M就够了、不会出现FULL GC 、也不会出现       内存溢出、一旦你的对象大于5M、比如10M的数据、 放不进去了、就会出现FULL gc 、FULL gc会把整个缓存全都收掉、瞬间缓存数据就没了、然后把10M的数据放进去、这就是弱引用、可以理解为这是一种服务降级、如果是强引用那就直接挂了
4、新建的对象也有可能直接进入老年代
  4.1、大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0、也就是说所有的默认都在新生代)来代表超过多大时就不再新生代分配,而是直接在老年代分配
  4.2、大的数组对象,切数组中无引用外部对象。
5、老年代大小无配置参数

java持久代(perm generation)

1、持久代=整个堆-年轻代大小-老年代大小
2、-XX:PermSize 最小 -XX:MaxPermSize 最大
设置持久代的大小,一般情况推荐把-XX:PermSize设置成 -XX:MaxPermSize的值为相同的值,因为永久代大小的调整也会导致堆内存需要触发fgc。
3、存放Class、Method元信息,其大小与项目的规模、类、方法的数量有关。一般设置为128M就足够,设置原则是预留30%的空间
刚开始设置了128M、随着程序的运行、java有一个叫lib的地方放了很多类库、这个类库并不是所有的都加载的、只有在用的时候或者系统初始化的时候会加载一部分、比如已经占了100M了、但是随着业务的运行会动态去类
库里加、把一些Class文件通过反射的方式装进去、这样你的内存不断增大、达到128M以后就挂了、就会报方法区溢出、怎么做?调大到256M、然后监控、超过阈值再调大、简单方式是调大、另外JDK里边有一个GC可以回收
如果能接受停机、就调大,简单、快速、已解决问题为主
4、永久代的回收方式
4.1、常量池中的常量,无用的类信息,常量的回收很简单,没有引用了就可以被回收
比如一个常量=5 它的意义就是个值、如果回收、发现它没被引用就被回收了
4.2、对于无用的类进行回收,必须保证3点:
类跟常量不一样、一个类里边可能有好多东西、比如这个类引用那个类、

  • 类的所有实例都已经被回收
  • 加载类的ClassLoader已经被回收
  • 类对象的Class对象没有被引用(即没有通过反射引用该类的地方)

JVM原理以及深度调优(二)的更多相关文章

  1. JVM原理与深度调优

    什么是jvm jvm是java虚拟机 运行在用户态.通过应用程序实现java代码跨平台.与平台无关.实际上是"一次编译,到处执行" 1.从微观来说编译出来的是字节码!去到哪个平台都 ...

  2. JVM原理与深度调优(一)

    什么是jvm jvm是java虚拟机 运行在用户态.通过应用程序实现java代码跨平台.与平台无关.实际上是"一次编译,到处执行" 1.从微观来说编译出来的是字节码!去到哪个平台都 ...

  3. JVM原理与深度调优(三)

    jvm垃圾收集算法 1.引用计数算法每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收.此方法简单,无法解决对象相互循环引用的问题.还有一个问题是如何解决精准计 ...

  4. (转)JVM原理讲解和调优

    背景:jvm实际调优在面试时候经常被问到,所以有必要认真总结一番. 转自:JVM原理讲解和调优 四.JVM内存调优 首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存 ...

  5. JVM原理讲解和调优

    一.什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现 ...

  6. Jvm原理剖析与调优之内存结构

    一些不得不说的概念 JVM JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机包括一套字节码指令集.一组寄存器.一个栈.一个 ...

  7. java JVM原理讲解和调优和gc

  8. 深入理解JVM虚拟机10:JVM常用参数以及调优实践

    转自http://www.rowkey.me/blog/2016/11/02/java-profile/?hmsr=toutiao.io&utm_medium=toutiao.io&u ...

  9. JVM基本配置与调优

    JVM基本配置与调优 JVM调优,一般都是针对堆内存配置调优. 如图:堆内存分新生代和老年代,新生代又划分为eden区.from区.to区. 一.区域释义 JVM内存模型,堆内存代划分为新生代和老年代 ...

随机推荐

  1. jmeter实现接口关联的两种方式:正则表达式提取器和json提取器看这篇就够了

    一.前言在开展接口测试或者是接口面试的过程中,我们会发现很多接口需要依赖前面的接口,需要我们动态从前面的接口返回中提取数据,也就是我们通常说的关联. 关联通俗来讲就是把上一次请求的返回内容中的部分截取 ...

  2. C Cow XOR 奶牛异或

    时间限制 : 10000 MS   空间限制 : 65536 KB 问题描述 农民约翰在喂奶牛的时候被另一个问题卡住了.他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一 ...

  3. 使用ElasticSearch赋能HBase二级索引 | 实践一年后总结

    前言:还记得那是2018年的一个夏天,天气特别热,我一边擦汗一边听领导大刀阔斧的讲述自己未来的改革蓝图.会议开完了,核心思想就是:我们要搞一个数据大池子,要把公司能灌的数据都灌入这个大池子,然后让别人 ...

  4. Light of future-冲刺Day 4

    目录 1.SCRUM部分: 每个成员进度 SCRUM 会议的照片 签入记录 代码运行截图 用户浏览界面 管理员浏览界面 2.PM 报告: 时间表 燃尽图 任务总量变化曲线 每名成员的贡献比 归属班级 ...

  5. Java引用的分类

    Java引用分为强引用.软引用.弱引用和虚引用. 强引用就是指在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被 ...

  6. 多线程之旅(Task 任务)

    一.Task(任务)和ThreadPool(线程池)不同       源码 1.线程(Thread)是创建并发工具的底层类,但是在前几篇文章中我们介绍了Thread的特点,和实例.可以很明显发现局限性 ...

  7. .Net微服务实践(五)[服务发现]:Consul介绍和环境搭建

    目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocel ...

  8. Java中如何通过try优雅地释放资源?

    时间紧迫,长话短说,今天,小明给大家同步一个知识点,使用try-with-resources来优雅地关闭资源. 1. 背景 其实,在JDK 7就已经引入了对try-with-resources的支持, ...

  9. C语言数据结构无向图

    #include<stdio.h>#include<stdlib.h>#define num 8struct nearnode{ int order; nearnode* pn ...

  10. Java第十七天,Set接口

    Set接口 1.特点 (1)不包含重复元素. (2)没有索引. (3)继承自Collection接口,所以Collection接口中的所有方法都适用于Set接口. 2.解析 (1)为什么不能包含重复元 ...