什么是 Java 对象分配率

类似“不可持续的内存分配率”和“你需要维持低的内存分配率”这样的短语看起都像是属于 Java 冠军(Java Champions)的专有词汇。复杂、吓人、充满神秘色彩。

这些词语经常出现,但是如果你深入了解这些概念,它的神秘色彩就烟消云散了。这篇文章将试着揭开上面这些术语的神秘面纱。

什么是内存分配率?我们为什么要关心它?

内存分配率是指单位时间内分配内存的总数量,通常用 MB/sec 表示。不过,如果你乐意,也可以用 PB/year 来表示。这就是全部的内容——没那么神秘,仅仅是指 Java 代码在一定时期内内存分配的大小。

不过只知道这一点没有太大的意义。如果你能忍受,我将带你在实践中应用这个概念。高分配率意味着你的程序存在性能问题。从实践角度来说,主要影响是使得 GC(Garbage Collection) 成为了瓶颈。从硬件角度来说,即使常用的硬件也能支持每核几 GB/sec 的分配率。而实际上,你的分配率不会超过 1 GB/sec/core。所以你可以放心,硬件基本不可能成为应用的瓶颈。

所以,当我们关注 GC 的时候,就可以和真实情况类比了——如果你创建很多的成员,之后就需要做很多清理工作。我们知道,JVM 建立垃圾回收机制需要知道内存分配率,由此来改变 GC 执行的频率和 GC 停顿的时间。

内存分配率的测量

我们开始测量内存分配率。我们设置 JVM 参数:-XX:+PrintGCDetails -XX:+PrintGCTimeStamps 来打开 GC 日志。现在,JVM 开始以下列方式记录 GC 停顿日志:

0.291: [GC (Allocation Failure) [PSYoungGen: 33280K->5088K(38400K)] 33280K->24360K(125952K), 0.0365286 secs] [Times: user=0.11 sys=0.02, real=0.04 secs]

0.446: [GC (Allocation Failure) [PSYoungGen: 38368K->5120K(71680K)] 57640K->46240K(159232K), 0.0456796 secs] [Times: user=0.15 sys=0.02, real=0.04 secs]

0.829: [GC (Allocation Failure) [PSYoungGen: 71680K->5120K(71680K)] 112800K->81912K(159232K), 0.0861795 secs] [Times: user=0.23 sys=0.03, real=0.09 secs]

根据上述 GC 日志,我们可以从年青代(Young Generation)上一次回收后的大小及下一次回收前的大小来计算出分配率。利用上面的例子,我们可以抽取出如下信息:

  • JVM 启动291毫秒后,加载的对象大小是33280K。第一次 minor GC 清理后,年青代剩余的对象大小是 5088K。
  • 启动446毫秒后,年青代占用的空间已经增长到38368K,并触发了下一次 GC,这次 GC 后,年青代占用的空间减少到5120K。
  • 启动829毫秒后,年青代的大小是71680K,GC 后再次减少到 5120K。

这些数据用如下的表格展示,计算出来的内存分配率添加年青代占用空间的后面:

事件 时间 添加年轻代之前 添加年轻代之后 已分配 分配率
1st GC 291ms 33,280KB 5,088KB 33,280KB 114MB/sec
2nd GC 446ms 38,368KB 5,120KB 33,280KB 215MB/sec
3rd GC 829ms 71,680KB 5,120KB 66,560KB 174MB/sec
Total 829ms N/A N/A 133,120KB 161MB/sec

有了这些信息,我们就可以说对这个特定软件,在测量期间的内存分配率是161 MB/sec。

影响分析

现在,通过这些信息,我们能够明白改变内存分配率,可以增加或减少 GC 停顿的频率,从而影响应用的吞吐率。首先,也是最重要的,你应该注意只有 Minor GC 清理年青代的停顿才会受影响。老年代(Old Generation)的清理,无论是频率还是持续时间都不直接受分配率的影响,但是受增长率(promotion rate)的影响,增长率是下一篇文章讨论的术语。

了解这些后,我们就只需要关注 Minor GC 的停顿,我们应该更进一步的去理解在年青代内部内存池的不同之处。因为内存分配是在 Eden 区中进行的,我们可以直接看 Eden 区的大小对分配率的影响。所以我们可以假设,随着 Eden 区的增长,minor GC 停顿频率频率会降低,应用就能满足更快的分配率。

事实上,当我们采用不同的 Eden 区大小(-XX:NewSize -XX:MaxNewSize 和 -XX:SurvivorRatio参数)来执行相同的实例时,我们可以看到两种不同的内存分配率:

  • 设置 Eden 区为100M,运行上面的例子,内存分配率降低到100MB/sec。
  • 增加个 Eden 区到1GB,增加的内存分配率接近 200MB/sec。

如果你仍然疑惑这为什么是对的——假设减少应用线程 GC 的频率,你就可以做更多的有用的工作。这样就可以生成更多的对象,从而支持更高内存分配率。

现在,在你得出“ Eden 区越大越好”的结论之前,你应该注意内存分配率可能不会直接关联应用的真实吞吐率。并且这只是一种侧重吞吐率的技术测量。内存分配率只影响 Minor GC 暂停应用线程的频率,但从整体的影响来说,你还需要考虑 Major GC 的停顿以及应用提供的业务操作。

时间: 2024-10-16 10:24:18

什么是 Java 对象分配率的相关文章

Java对象分配内存时的内存图

摘自高琪老师的JAVA教程. Java对象分配内存时的内存图

java对象分配

1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描.而我们的很多对象都是朝生夕死的,如果分代的话,我们把新创建的对象放到某一地方,当GC的时候先把这块存“朝生夕死”对象的区域进行回收,这样就会腾出很大的空间出来. 2.年轻代中的GC     HotSpot JVM把年轻代分为了三部分:1个Eden

JAVA 对象分配过程

1. 在JAVA中,对象的分配一般使用new关键字.  当虚拟机遇到new指令时,会先检查该指令所包含的参数在常量池中能否找到一个符号引用,并检查该符号引用所代表的类是否被加载.解析和初始化. 如果没有,则会先执行类的加载过程. 2. 类加载完成后,会为该对象分配内存空间.一个对象需要多大的内存空间在类加载完成后就确定了. 分配内存有两种方法,依据内存空间是否规整来确定. 如果被内存空间是规整的,只要把空闲指针向空闲内存方向挪动即可,这种方法称为“指针碰撞”: 如果内存空间不是规整的,需要有一个

JVM之对象分配:栈上分配 & TLAB分配

1. Java对象分配流程 2. 栈上分配 2.1 本质:Java虚拟机提供的一项优化技术 2.2 基本思想: 将线程私有的对象打散分配在栈上 2.3 优点: 2.3.1 可以在函数调用结束后自行销毁对象,不需要垃圾回收器的介入,有效避免垃圾回收带来的负面影响 2.3.2 栈上分配速度快,提高系统性能 2.4 局限性: 栈空间小,对于大对象无法实现栈上分配 2.4 技术基础: 逃逸分析 2.4.1 逃逸分析的目的: 判断对象的作用域是否超出函数体[即:判断是否逃逸出函数体] //user的作用域

源码分析:Java对象的内存分配

Java对象的分配,根据其过程,将其分为快速分配和慢速分配两种形式,其中快速分配使用无锁的指针碰撞技术在新生代的Eden区上进行分配,而慢速分配根据堆的实现方式.GC的实现方式.代的实现方式不同而具有不同的分配调用层次. 下面就以bytecodeInterpreter解释器对于new指令的解释出发,分析实例对象的内存分配过程: 一.快速分配 1.实例的创建首先需要知道该类型是否被加载和正确解析,根据字节码所指定的CONSTANT_Class_info常量池索引,获取对象的类型信息并调用is_un

java内存分配和String类型的深度解析(转)

一.引题 在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析 关于String的许多令人迷惑的问题.下面是本文将要涉及到的一些问题,如果读者对这些问题都了如指掌,则可忽略此文. 1.java内存具体指哪块内存?这块内存区域为什么要进行划分?是如何划分的?划分之后每块区域的作用是什么?如何设置各个区域的大小? 2.String类型在执行连接操作时,效率为什么会比StringBuffer或者StringBu

JVM —— Java 对象占用空间大小计算

零. 为什么要知道 Java 对象占用空间大小 缓存的实现: 在设计 JVM 内缓存时(不是借助 Memcached. Redis 等), 需要知道缓存的对象是否会超过 JVM 最大堆限制, 如果会超过要设置相应算法如 LRU 来丢弃一部分缓存数据以满足后续内容的缓存 JVM 参数设置: 如果知道对象会被创建, 可以帮助判断 -Xmx 需要设置多少 只是为了好玩 一. 对象的内存布局 HotSpot 虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instan

Java内存分配与垃圾回收

1.JVM管理的内存包含下图所示的几个运行时数据区域,其中方法区和堆为线程共享的数据区域,程序计数器,虚拟机栈以及本地方法栈为线程私有的数据区域. 程序计数器:可以看做是当前线程所执行的字节码的行号指示器,告诉字节码解释器该读取哪条指令 虚拟机栈:生命周期和线程相同,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法从调用到完成的过程就对应了一个栈帧在虚拟机中入栈到出栈的过程.栈中存放了编译器可知的各种基本数据类型和对象引用. 本地方法栈:与

Java对象及其引用 (1)

Java对象及其引用 [文章转载自:http://zwmf.iteye.com/blog/1738574] 说明:所有转载为个人学习存档使用,凡转载内容均注明转载出处.以后不再说明. 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术.把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路. 为便于说明,我们先定