JVM内存结构、垃圾回收那点事
翻看电脑的文件夹,无意看到了9月份在公司做的一次分享,浏览了一下"婆婆特",发现自己在ppt上的写的引导性问题自己也不能确切的回答出来,哎,知识这东西,平时不常用的没些日子就生疏了。于是,本小白决定把他整理下来,不敢班门弄斧,对于入门的同学可以快速了解虚拟机的大概,有错误的地方请批评指正。
一、java虚拟机的内存结构
public class ReferenceCountGc {
public Object field = null;
public static void main(String[] args) {
ReferenceCountGc objA = new ReferenceCountGc();
ReferenceCountGc objB = new ReferenceCountGc();
objA.field = objB;
objB.field = objA;
objA = null;
objB = null;
System.gc();
}
}
当程序执行到System.gc()时,是否会回收对象objA和objB?
引用计数方法:给对象一个计数器,当对象被引用时就+1,释放掉引用-1,当为0时及不会再被引用。但引用计数方法的Bug是无法解决对象循环引用的问题,但并不是此算法没有用武之地,在很多场景下会使用到这个算法。但java的垃圾回收并没有使用。上面的程序如果使用的是引用计数算法则不会被回收,但虚拟机却使用根搜索算法。
根搜索算法即设定一个对象称为GC root ,从这个节点向下进行搜索,搜索所走过的路径称为引用链,当GC root没有任何引用链相连即在图论中不可到达,则证明此对象不可用
由此来看看,对象死后,垃圾回收算法;
标记-清除算法 复制算法
灰色矩形框为可回收对象,标记-清除算法就是把可回收的对象进行标记,标记到一定次数则清除掉。从图中可以明显看出,该算法的弊端是会产生大量的磁盘碎片,没有一整片连续的空间,当遇到占用连续的内存空间较多的对象时,由于内存放不下该对象,会提前进行垃圾回收,致使虚拟机垃圾回收频繁,影响性能
为了规避标记清除算法的弊端,出现了复制算法,复制算法将内存一份为二,垃圾回收时将使用的内存中的存活对象,拷贝到另一半内存中,然后把左侧内存区域完全清除掉,上图只是演示了复制算法,但并非一分为二,使用和保留的空间是1:1,可以根据实际情况对虚拟机参数进行调整。此算法的弊端是要保留内存空间,会将可用内存变少。
标记整理算法: 分代收集算法:
标记整理算法:绿色和蓝色区域都代表存活对象,当进行垃圾回收时把存活对象依次移到最左边,移动后将其余内存空间清空。
分代收集算法:如图,其实就是没有算法。。。把以上3种算法进行综合运用,前面说过堆是有划分的,简单分为新生代和老年代,分代收集就是根据不同代的特点应用不同的垃圾回收算法。
三、java内存分配
java的自动内存管理解决了两个问题,一是给对象分配内存,二是回收分配给对象的内存,前面我们讲了回收分配给对象的内存,下面我们来看看给对象分配内存
java堆分为新生代,老年代(终身代)和永久代。
新生代和老年代的默认比值为1:2即新生代占堆总内存的1/3,可以通过 –Xms(初始堆大小)、-Xmx (最大堆大小)来改变。
新生代又分为Eden区、From survivor区、To survivor区,Eden:From:To 为 8:1:1,可以通过–XX:SurvivorRatio 参数设定。
JVM每次只会使用From区和survivor区中的一块(Form survivor或To survivor),很明显是为了在垃圾回收的时候将存活对象移到另外一个空闲的survivor区(如果空间足够,否则直接进入老年代),因此垃圾回收所使用的算法是复制算法。
新生的对象会被分配到新生代,新生代的特点是朝生夕死,对象存活的时间短,迭代快。发生在新生代的垃圾回收叫minor GC,minor Gc进行的相对频繁,消耗较full GC少,而Full GC是发生在老年代的垃圾回收,采用的是标记-清除算法。老年代进行一次垃圾回收比新生代话费时间长,进行的也没有老年代频繁,同时要尽量减少老年代的垃圾回收,因为回收速度慢且在进行时影响虚拟机性能,使虚拟机响应变慢,最直接的感觉是应用程序的响应速度变慢。
什么情况下,对象会被分配到老年代?
从上图中明显可以到3点:
大对象:什么是大对象,大对象就是需要连续占用很多内存空间的对象比如很长的字符串和数组。虚拟机通过-XX:PretrnureSizeThreshold设计大过指定大小的对象之间进入老年代,即时没有超过指定大小,在进行minor GC时通常也会因为survivor区不够用而被转移到老年代。
通过设置MaxTenuringThreshold参数: 这个参数是进行年龄设置的,超过这个年龄的会进入老年代。什么是年龄?在新生代进行minor GC的时候,每进行一次,存活下来的对象年龄+1,默认年龄超过15的会进入老年代。15这个数值也可以通过MaxTenuringThreshold参数改变。
Survivor空间中相同年龄所有对象大小的总和大于survivor空间的一半,所有大于或者等于该年龄的对象直接进入老年代,这句话比较拗口,但就是这个意思,看不懂的多看几遍就好了。。。
前面讲了这么多参数,如何设置虚拟机参数?可以通过IDE进行设置,不论是调整空间大小,还是设置对象的年龄进入老年代,如下图
三、我们开发中应注意的问题
从虚拟机上可以看出,主要是避免full GC的次数,减少朝生夕死的大对象,对虚拟机内存进行优化,在日常开发中写程序的主要注意的是
不要使用长字符串 如:String x = new String(“XXXXXXXXXXXX”) StringBuffer stringBuffer = new StringBuffer()StringBuffer对象的append()方法。当然,考虑到线程安全问题,使用StringBuilder.
JVM内存结构、垃圾回收那点事的更多相关文章
- Java进阶 JVM 内存与垃圾回收篇(一)
JVM 1. 引言 1.1 什么是JVM? 定义 Java Vritual Machine - java 程序的运行环境(Java二进制字节码的运行环境) 好处 一次编译 ,到处运行 自动内存管理,垃 ...
- Java内存与垃圾回收调优
Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多个独立的部分.广泛地说,JVM堆内存被分为两部分——年轻代(Young Generation)和老年代(Old Generat ...
- 【转】Java内存与垃圾回收调优
要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多 ...
- 面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
一.JVM内存结构 ▷ 谈及内存结构各个部分的数据交互过程:还可以再谈及生命周期.数据共享:是否GC.是否OOM 答:jvm 内存结构包括程序计数器.虚拟机栈.本地方法栈.堆.方法区:它是字节码运行时 ...
- 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...
- 【转】jvm内存结构
JVM的基本结构 包括四部分:类加载器.执行引擎.内存区(运行时数据区).本地方法接口 类加载器:jvm启动时或类运行时将需要的class文件加载到JVM中. JVM内存申请过程如下: JVM 会试图 ...
- 【JVM】JVM系列之垃圾回收(二)
一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此.所以,垃圾回收是必须的. 二. ...
- JVM内存结构之三--持久代
本文会介绍一些JVM内存结构的基本概念,然后很快会讲到持久代,来看下Java SE 8发布后它究竟到哪去了. 基础知识 JVM只不过是运行在你系统上的另一个进程而已,这一切的魔法始于一个java命令. ...
- 最简单例子图解JVM内存分配和回收
一.简介 JVM采用分代垃圾回收.在JVM的内存空间中把堆空间分为年老代和年轻代.将大量(据说是90%以上)创建了没多久就会消亡的对象存储在年轻代,而年老代中存放生命周期长久的实例对象.年轻代中又被分 ...
- JVM内存结构
前言 在Java语言开发过程中,out of memory错误是很常见的一种错误.对于JVM的内存结构有更深入的了解,更更好的帮我们排查此类问题,有效的避免此类问题发生.在JAVA 8中内存结构有进行 ...
随机推荐
- 【GoLang】golang底层数据类型实现原理
虽然golang是用C实现的,并且被称为下一代的C语言,但是golang跟C的差别还是很大的.它定义了一套很丰富的数据类型及数据结构,这些类型和结构或者是直接映射为C的数据类型,或者是用C struc ...
- Split Array Largest Sum
Given an array which consists of non-negative integers and an integer m, you can split the array int ...
- 第十天 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)
1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...
- JAVA手记 JAVA入门(安装+Dos下运行)
JAVA入门特供= =,今天设置环境变量后用dos运行的时候发现出现“找不到或无法加载主类”,索性查了些资料重新看了看JAVA入门的部分. 声明:我的笔记本暂时用的是Win10系统,Windows其他 ...
- js 中 toString( ) 和valueOf( )
1.toString()方法:主要用于Array.Boolean.Date.Error.Function.Number等对象转化为字符串形式.日期类的toString()方法返回一个可读的日期和字符串 ...
- 【leetcode】Minimum Depth of Binary Tree (easy)
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- 【leetcode】Validate Binary Search Tree(middle)
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...
- Gym 100703K Word order 贪心
题目链接 题意:给定一个长度为n的字符串,字符串仅由"F","N","A"三种字符组成,现有一种操作P,即把两个相邻的字符调换位置.要求把所 ...
- SEH-关于捕获memcpy的异常
网上有说memcpy是C语言写的,没有异常处理机制. 但是貌似SEH可以处理. SEH("Structured Exception Handling"),即结构化异常处理·是(wi ...
- mongodb配置文件.conf
启动方式 ./bin/mongod -f MongoDB.conf 会看到 about to fork child process, waiting until server is ready for ...