文档章节

JAVA基础第三章-类与对象、抽象类、接口

SEOwhywhy
 SEOwhywhy
发布于 2018/12/12 10:13
字数 1821
阅读 8
收藏 1

  前言
  
  标题没有看错,真的是让我写个 bug!
  
  刚接到这个需求时我内心没有丝毫波澜,甚至还有点激动。这可是我特长啊;终于可以光明正大的写 bug 了🙄。
  
  先来看看具体是要干啥吧,其实主要就是要让一些负载很低的服务器额外消耗一些内存、CPU 等资源(至于背景就不多说了),让它的负载可以提高一些。
  
  JVM 内存分配回顾
  
  于是我刷刷一把梭的就把代码写好了,大概如下:
  
  写完之后我就在想一个问题,代码中的 mem 对象在方法执行完之后会不会被立即回收呢?我想肯定会有一部分人认为就是在方法执行完之后回收。
  
  我也正儿八经的去调研了下,问了一些朋友;果不其然确实有一部分认为是在方法执行完毕之后回收。
  
  那事实情况如何呢?我做了一个试验。
  
  我用以下的启动参数将刚才这个应用启动起来。
  
  java -Djava.rmi.server.hostname=10.xx.xx.xx
  
  -Djava.security.policy=jstatd.all.policy
  
  -Dcom.sun.management.jmxremote.authenticate=false
  
  -Dcom.sun.management.jmxremote.ssl=false
  
  -Dcom.sun.management.jmxremote.port=8888
  
  -Xms4g -Xmx4g  -jar bug-0.0.1-SNAPSHOT.jar
  
  这样我就可以通过 JMX 端口远程连接到这个应用观察内存、GC 情况了。
  
  如果是方法执行完毕就回收 mem 对象,当我分配 250M 内存时;内存就会有一个明显的曲线,同时 GC 也会执行。
  
  这时观察内存曲线。
  
  会发现确实有明显的涨幅,但是之后并没有立即回收,而是一直保持在这个水位。同时左边的 GC 也没有任何的反应。
  
  用 jstat 查看内存布局也是同样的情况。
  
  不管是 YGC,FGC 都没有,只是 Eden 区的使用占比有所增加,毕竟分配了 250M 内存嘛。
  
  那怎样才会回收呢?
  
  我再次分配了两个 250M 之后观察内存曲线。
  
  发现第三个 250M 的时候 Eden 区达到了 98.83% 于是再次分配时就需要回收 Eden 区产生了 YGC。
  
  同时内存曲线也得到了下降。
  
  整个的换算过程如图:
  
  由于初始化的堆内存为 4G,所以算出来的 Eden 区大概为 1092M 内存。
  
  加上应用启动 Spring 之类消耗的大约 20% 内存,所以分配 3 次 250M 内存就会导致 YGC。
  
  再来回顾下刚才的问题:
  
  mem 对象既然在方法执行完毕后不会回收,那什么时候回收呢。
  
  其实只要记住一点即可:对象都需要垃圾回收器发生 GC 时才能回收;不管这个对象是局部变量还是全局变量。
  
  通过刚才的实验也发现了,当 Eden 区空间不足产生 YGC 时才会回收掉我们创建的 mem 对象。
  
  但这里其实还有一个隐藏条件:那就是这个对象是局部变量。如果该对象是全局变量那依然不能被回收。
  
  也就是我们常说的对象不可达,这样不可达的对象在 GC 发生时就会被认为是需要回收的对象从而进行回收。
  
  在多考虑下,为什么有些人会认为方法执行完毕后局部变量会被回收呢?
  
  我想这应当是记混了,其实方法执行完毕后回收的是栈帧。
  
  它最直接的结果就是导致 mem 这个对象没有被引用了。但没有引用并不代表会被马上回收,也就是上面说到的需要产生 GC 才会回收。
  
  所以使用的是上面提到的对象不可达所采用的可达性分析算法来表明哪些对象需要被回收。
  
  当对象没有被引用后也就认为不可达了。
  
  这里有一张动图比较清晰:
  
  当方法执行完之后其中的 mem 对象就相当于图中的 Object 5,所以在 GC 时候就会回收掉。
  
  优先在 Eden 区分配对象
  
  其实从上面的例子中可以看出对象是优先分配在新生代中 Eden 区的,但有个前提就是对象不能太大。
  
  以前也写过相关的内容:
  
  大对象直接进入老年代
  
  而大对象则是直接分配到老年代中(至于多大算大,可以通过参数配置)。
  
  当我直接分配 1000M 内存时,由于 Eden 区不能直接装下,所以改为分配在老年代中。
  
  可以看到 Eden 区几乎没有变动,但是老年代却涨了 37% ,根据之前计算的老年代内存 2730M 算出来也差不多是 1000M 的内存。
  
  Linux 内存查看
  
  回到这次我需要完成的需求:增加服务器内存和 CPU 的消耗。
  
  CPU 还好,本身就有一定的使用,同时每创建一个对象也会消耗一些 CPU。
  
  主要是内存,先来看下没启动这个应用之前的内存情况。
  
  大概只使用了 3G 的内存。
  
  public  class Human implements Animals
  
  2 {
  
  3     private String name;
  
  4     private String sex;
  
  5     private int weight;
  
  6     private int heiht;
  
  7     public String getName() {
  
  8         return name;
  
  9     }
  
  10
  
  11     public void setName(String name) {
  
  12         this.name = name;
  
  13     }
  
  14
  
  15     public String getSex(www.quwanyule157.com) {
  
  16         return sex;
  
  17     }
  
  18
  
  19     public void setSex(String sex) {
  
  20         this.sex = sex;
  
  21     }
  
  22
  
  23     public int getWeight() {
  
  24         return weight;
  
  25     }
  
  26
  
  27     public void setWeight(www.feifanyule.cn/ int weight) {
  
  28         this.weight =www.michenggw.com weight;
  
  29     }
  
  30
  
  31     public int getHeiht(www.yigouyule2.cn) {
  
  启动应用之后大概只消耗了 600M 左右的内存。
  
  为了满足需求我需要分配一些内存,但这里有点需要讲究。
  
  不能一直分配内存,这样会导致 CPU 负载太高了,同时内存也会由于 GC 回收导致占用也不是特别多。
  
  所以我需要少量的分配,让大多数对象在新生代中,为了不被回收需要保持在百分之八九十。
  
  同时也需要分配一些大对象到老年代中,也要保持老年代的使用在百分之八九十。
  
  这样才能最大限度的利用这 4G 的堆内存。
  
  于是我做了以下操作:
  
  先分配一些小对象在新生代中(800M)保持新生代在90%
  
  接着又分配了老年代内 *(100%-已使用的28%);也就是 2730*60%=1638M 让老年代也在 90% 左右。
  
  效果如上。
  
  最主要的是一次 GC 都没有发生这样也就达到了我的目的。
  
  最终内存消耗了 3.5G 左右。
  
  总结
  
  虽说这次的需求是比较奇葩,但想要精确的控制 JVM 的内存分配还是没那么容易。
  
  需要对它的内存布局,回收都要有一定的了解,写这个 Bug 的过程确实也加深了印象,如果对你有所帮助请不要吝啬你的点赞与分享。

© 著作权归作者所有

SEOwhywhy
粉丝 8
博文 155
码字总数 342404
作品 0
私信 提问
大数据开发培训:0基础学习Java编程语言有哪些知识点?

Java 技术通用、高效、具有平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网等,学习Java首先要知道学习知识点有哪些。在这就用加米谷大数据培训...

加米谷大数据
2018/07/25
2
0
01 - JavaSE之基础及面向对象

JAVA基础知识 Java 是SUN(Stanford University Network,斯坦福大学网络公司)1995年推出的一门面向 Internet 的高级编程语言。 Java 虚拟机(JVM:Java Virtual Machine) JRE(Java Runtim...

fengdaoting
2018/01/07
0
0
[敏捷JAVA读书笔记-java基础部分] 第一章

今年年初到海淀图书城购买了一个Agile Java(敏捷java),匆匆翻看了几章就束之高阁,最近在班车上无事可做,拿出来重读一下,一方面学一下TDD,一方面梳理一下自己的JAVA基础知识,读书的时间...

穿越星辰
2010/05/13
110
0
做几道基础的Java测试题,看看最近有进步吗?欢迎来学习

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

启示录是真的
2018/05/24
0
0
《Kotin 编程思想·实战》目录

《Kotin 编程思想·实战》目录 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 第1章 JVM语言家族概览 1.1 编程语言简史 1.2 程序执行的三种方...

程序员诗人
2017/06/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

查看线上日志常用命令

cat 命令(文本输出命令) 通常查找出错误日志 cat error.log | grep 'nick' , 这时候我们要输出当前这个日志的前后几行: 显示file文件里匹配nick那行以及上下5行 cat error.log | grep -C ...

xiaolyuh
18分钟前
3
0
六、Java设计模式之工厂方法

工厂方法定义: 定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行 类型:创建型 工厂方法-使用场景: 创建对象需要大量重复的代码 ...

东风破2019
24分钟前
3
0
win服务器管理遇到的一系列问题记录

有些小伙伴在使用iis7远程桌面管理工具的时候总是会遇到一系列的问题,下面就是为大家介绍一下服务器日常管理过程中出现的问题及我的解决办法和心得。希望能帮到大家。   拒绝服务器重新启...

1717197346
31分钟前
2
0
flutter 剪切板 复制粘贴

复制粘贴功能 import 'package:flutter/services.dart'; Clipboard.setData(ClipboardData(text:_text));Clipboard.getData;...

zdglf
34分钟前
3
0
如何保证消息的可靠性传输?或者说,如何处理消息丢失的问题?

面试题 如何保证消息的可靠性传输?或者说,如何处理消息丢失的问题? 面试官心理分析 这个是肯定的,用 MQ 有个基本原则,就是数据不能多一条,也不能少一条,不能多,就是前面说的重复消费...

米兜
34分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部