内存碎片

面试题:JVM,GC垃圾回收机制

帅比萌擦擦* 提交于 2020-03-09 17:00:12
收集了有关Java中GC垃圾回收机制的一些知识点,帮助自己理解。 GC(垃圾收集),那收集回收的是什么呢? 是内存 ,所以在了解垃圾回收机制之前,要对Java内存有一个了解。 一:Java内存 图解: 私有内存区:伴随线程的产生而产生 ,一旦线程终止,私有内存区也会自动消除 程序计数器:指示当前程序执行到了哪一行,执行 Java方法 时记录正在执行的虚拟机 字节码指令地址 ;执行 本地方法 时,计数器值为 null 虚拟机栈:用于执行 Java方法 ,栈帧存储 局部变量表,操作数栈 , 动态链接,方法返回地址 和一些额外的符加信息。程序执行时入栈;执行完成后栈帧出栈。 Java堆:Java虚拟机管理的内存中最大的一块,所有 线程共享 ,几乎 所有的对象实例和数组 都在这里分配内存。GC主要就是在Java堆中进行的。 堆内存又分为:新生代(新生代又分为Eden80%,Survivor20%)和老年代(Old),并且一般新生代的空间比老年代大。 方法区:只有一个方法区共享。实际也是堆,只是用于 存储类 , 常量 相关的信息,来存放程序中永远不变或唯一的内容( 类信息【Class对象】 , 静态变量,字符串常量 等)。但是已经被最新的 JVM 取消了。现在,被加载的类作为元数据加载到底层操作系统的本地内存区。 了解了Java内存,接下来就来了解一下GC原理: 二、垃圾回收机制 一

JVM运行时数据区域

三世轮回 提交于 2020-03-09 05:17:22
一、运行时数据区域 相应脑图 程序计数器 记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。 Java 虚拟机栈 每个 Java 方法在执行的同时会创建一个 栈帧 用于 存储局部变量表 、 操作数栈 、 常量池引用等信息 。 从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。 对于执行引擎来说,活动线程中,只有栈顶的栈帧是有效的,称为 当前栈帧 ,这个栈帧所关联的方法称为 当前方法 。 执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作。 操作数栈: 一个后进先出(Last-In-First-Out)的操作数栈,也可以称之为表达式栈(Expression Stack)。 操作数栈和局部变量表在访问方式上存在着较大差异,操作数栈并非采用访问索引的方式来进行数据访问的, 而是**通过标准的入栈和出栈操作来完成一次数据访问**。 每一个操作数栈都会拥有一个明确的栈深度用于存储数值,一个32bit的数值可以用一个单位的栈深度来存储,而2个单位的栈深度则可以保存一个64bit的数值, 当然操作数栈所需的容量大小在编译期就可以被完全确定下来,并保存在方法的Code属性中。 可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小: java -Xss512M HackTheJava 该区域可能抛出以下异常:

面试题之JVM内存区域

余生颓废 提交于 2020-03-09 05:15:40
1、Java内存区域(运行时数据区域):   jdk1.8之前:虚拟机运行内存分栈、堆和方法区这几种。 栈:虚拟机栈、本地方法栈、程序计数器。(线程私有,每个线程都拥有各自的) 程序计数器:一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。主要有2个作用: 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪里了。 注意:唯一一个不会出现OutOfMemoryError的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。 Java虚拟机栈:生命周期与线程相同(随着线程创建而创建,随着线程死亡而死亡),描述的是Java方法执行的内存模型,每次方法调用的数据都是通过栈传递的。Java内存大概就是堆内存和栈内存,栈是虚拟机栈或是虚拟机栈中局部变量表部分。(实际上,Java虚拟机栈是由一个个栈帧组成,每个栈帧中都拥有:局部变量表、操作数、动态链接、方法出口信息) 局部变量表主要存放了编译器可知的各种数据类型 (boolean、byte、char、short、int、float、long、double)、 对象引用 (reference类型,不同于对象本身,可能是指向一个代表对象起始地址的引用指针

堆栈的详细讲解

不想你离开。 提交于 2020-03-09 04:57:02
在讲解堆栈之前,先让我们对堆栈有一个感性的认识 使用栈 :就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆 :就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。 再了解一下堆栈的定义和函数调用的过程中堆栈的样子 记住堆栈定义中标黄的重点,对理清函数调用过程帮助非常大。 堆栈的定义 :堆栈是一种数据结构,具体是一个特定的存储区或寄存器。堆栈都是一种数据项按序排列的数据结构。 只能在一端(称为栈顶(top))对数据项进行插入和删除,也就是它的一端是固定的,另一端(栈顶)是浮动的 ,严格按照“先进后出”的原则存取,位于其中间的元素,必须在其栈上部(后进栈者)诸元素逐个移出后才能取出。 因而栈顶地址总是小于等于栈的基地址。 #include <stdio.h> void __stdcall func(int param1,int param2,int param3) { int var1=param1; int var2=param2; int var3=param3; printf("0x%08x\n",param1); //打印出各个变量的内存地址 printf("0x%08x\n",param2); printf("0x%08x\n\n"

JVM,DVM虚拟机

允我心安 提交于 2020-03-09 00:44:59
Java虚拟机–JVM,类加载器,双亲委派 https://www.iteye.com/blog/welcome66-2216572 1、JVM(Java Virtual Machine),java虚拟机 JVM就是虚拟出来的计算机,有自己完善的架构,处理器,堆栈,寄存器,指令系统。使用jvm就是为了支持与操作系统无关,java跨平台的原理,因为java代码都在这上运行, .java 文件通过javac命令编译后生成. class 字节码文件,JVM的java解释器负责把.class字节码文件转化为特定的机器码文件运行。 1.进程级别,守护线程和非守护线程(用户线程) 守护线程:后台线程,为前台线程提供便利服务,比如GC线程。不要在守护线程中执行业务逻辑操作(比如对数据的读写等)。 非守护线程:前台线程 设置守护线程: public final void setDaemon ( boolean on ) 判断守护线程: public final boolean isDaemon ( ) 2.生命周期: 启动:启动java是开启,起点是public static void main 运行:main起点,两种线程:守护线程(JVM),非守护线程(JAVA),java也可以创建自己的守护线程 消亡:程序终止则退出,也可以用System.exit或Runtime类来退出 3.体系结构

伙伴系统和slab机制

*爱你&永不变心* 提交于 2020-03-08 22:17:34
伙伴系统 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表。四级页表分别为: 页全局目录(Page Global Directory) 页上级目录(Page Upper Directory) 页中间目录(Page Middle Directory) 页表(Page Table) 页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址,每一个页表项指向一个页框。Linux中采用4KB大小的页框作为标准的内存分配单元。 在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。 为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。 假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块

2. 影响mysql性能的因素

我的梦境 提交于 2020-03-08 17:32:57
影响mysql性能的几个方面: 1. 服务器硬件 2. 服务器操作系统 3. 数据库存储引擎 4. 数据库参数配置 5. 数据库结构设计和SQL语句 服务器硬件: 1. CPU: CPU密集型的应用,应选用频率更高的CPU而不是更多的CPU WEB类的应用,CPU核心数量比频率重要 2. 内存: 内存越多越好,内存对读、写都有作用 内存频率越高速度越快,应选择主板支持的最大内存频率,单条容量尽可能大 3. 磁盘: 传统机器硬盘:1.存储容量 2.传输速度 3.访问时间 4.主轴转速 5.物理尺寸 RAID(磁盘冗余阵列): 1.RAID 0,2块以上的硬盘组成,没有冗余和错误修复能力 2.RAID 1,磁盘镜像,2块硬盘组成,有冗余 3.RAID 5,分布式奇偶性校验阵列,3块以上的硬盘组成,任意一个盘数据失效时可以重建,更多盘数据失效时无法重建 4.RAID 10,分片镜像,RAID 0和RAID 1组合,4块以上的硬盘组成,对比RAID 5重建更简单,速度更快 固态存储SSD或PCI-E卡: 比机械硬盘有更好的随机读写性能 比机械硬盘能更好的支持并发 比机械硬盘更容易损坏 适用于存在大量随机I/O的场景 适用于解决单线程负载的I/O瓶颈 网络存储SAN和NAS: SAN的随机读写慢,不如本地RAID磁盘 NAS设备使用网络连接,通过基于文件的协议如NFS或SMB来访问

JVM--垃圾收集器以及内存分配

为君一笑 提交于 2020-03-08 14:37:07
概述   在jvm中,实现了多种垃圾收集器,包括:串行垃圾收集器、并行垃圾收集器、CMS(并发)垃圾收集器、G1垃圾收集器 串行垃圾收集器   串行垃圾收集器,是指使用单线程进行垃圾回收,垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停,等待垃圾回收的完成。这种现象称之为STW(Stop-The-World)。   对于交互性较强的应用而言,这种垃圾收集器是不能够接受的。   一般在Javaweb应用中是不会采用该收集器的。 测试代码 public class TestGC { public static void main(String[] args) throws Exception { List<Object> list = new ArrayList<Object>(); while (true) { int sleep = new Random().nextInt(100); if (System.currentTimeMillis() % 2 == 0) { list.clear(); } else { for (int i = 0; i < 10000; i++) { Properties properties = new Properties(); properties.put("key_" + i, "value_" + System

Java垃圾回收算法

穿精又带淫゛_ 提交于 2020-03-08 12:57:53
1.标记-清除算法 概念 标记阶段:先通过根节点,标记所有从根节点开始的可达对象,因此,未被标记的对象就是未被引用的垃圾对象; 清除阶段:清除所有未被标记的对象。 缺点: 标记和清除的过程效率不高(标记和清除都需要从头便利到尾) 标记清除后会产生大量不连续的碎片。 2.复制算法 概念: 将原有的内存空间氛围两块,每次只是用其中一块,在垃圾回收时,将正在使用放内存中的存活的对象复制到位使用的内存块中,饭后清除正在使用放内存块中放所有对象。 优点: 这样使得每次都是对整个搬去与进行回收,内存分配时也就不用考虑内存碎片等情况,只要移动堆顶指针按顺序分配内存即可,实现简单,运行效率高。 缺点:空间的浪费 从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行。 现在的商业虚拟机都采用这种手机算法来回收新生代,新生代的对象98%都是朝生夕死的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块比较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性的复制到另外一个Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是所,每次新生代中可使用内存空间为整个新生代容量的90%

JVM系列(二) — Java垃圾收集介绍

柔情痞子 提交于 2020-03-08 12:37:52
这篇文章主要从以下几个方面介绍垃圾收集的相关知识   一、判断对象是否已死   二、主流垃圾收集算法   三、内存分配与回收策略   本章节主要从以下几个思考点着手介绍垃圾回收的相关知识:哪些内存需要回收?什么时候回收?如何回收?这也是经典的学习一个知识点的3h方法:what? when? how? 上一个章节已经介绍jvm运行时数据区的内存分布,垃圾回收主要发生在堆这个区,也就是众多对象实例呆着的地方 一、如何判断对象已死?   相信面试过高级java的工程师肯定遇到过面试官这样的问题:两个对象之间互相循环引用,如何回收?换句话说如何判断这两个对象已死?   这里就引出了一个经典算法:引用计数法。是这样设计的:给对象添加一个引用计数器,每当这个对象被引用时,计数器值+1,引用失效时,计数值-1,任何时刻,计数为0 的对象就是不可能再被使用的对象   回到上面的例子,它很难解决互相引用的对象这种情况,于是导致GC无法回收他们   于是出现了另一个经典算法:可达性分析算法,基本思路是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链, 当一个对象到GC Roots没有任何引用链相连,或者称从GC Roots到这个对象不可达时,则证明这个对象是不可用的   作为GC Roots的对象一般有以下几种:虚拟机栈中引用的对象