本地线程

JVM探索之——内存管理(一)

我们两清 提交于 2019-12-18 05:53:11
本系列的 第一篇文章 ,预计本系列最后面会有两三个案例。 Java与C、C++不一样Java不需要Coder进行手动内存管理,而这一切都交给JVM进行自动内存管理,这从某种程度上来说也减轻了我们Coder不少的编码量,而我们是否还有必要了解JVM的内存管理机制呢,答案是否定的;因为Java也会和C、C++一样发生内存泄漏、内存溢出,尽管它发生这些事故会少很多,但一旦发生了而你又不了解他的内存管理机制这将是非常棘手的问题;还有个原因就是Java是运行在JVM上的,而不能JVM参数可能会影响到程序的执行性能,我们要想JVM在具体的应用中达到最优的性能那就必须了解JVM的内部机制;废话不多说现在开始JVM探索系列之——内存管理 根据《Java虚拟机规范》所规定的,Java虚拟机执行Java程序时它他管理的内存划分为几个区域,也就是运行时数据区(Run-Time Data Areas);这些区域的功能、生命周期各不相同,主要分为两大类:一种是随着JVM进程的启动而创建,随JVM进程消亡而销毁;一种是随着线程的创建而创建,随着线程的销毁而销毁,《Java虚拟机规范》规定的内存区域有如下图: 红色边框的两块区域为所有线程共享的(JVM进程的启动而创建、进程消亡而销毁) 其他三块区域为线程隔离的(线程的创建而创建,随着线程的销毁而销毁) 如图所示,运行时数据区(Run-time Areas)分为

JVM内存区域的划分(内存结构或者内存模型)

会有一股神秘感。 提交于 2019-12-18 04:27:59
运行时数据区域: 根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。 程序计数器(线程私有):    是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为 “线程私有”的内存。   正在执行java方法的话,计数器记录的是 虚拟机字节码指令的地址(当前指令的地址) 。如果还是 Native方法,则为空 。   这个内存区域是唯一一个在虚拟机中 没有规定任何 OutOfMemoryError情况的区域。 Java 虚拟机栈(线程私有):    也是线程私有的。   每个方法在执行的时候会创建一个栈帧,存储了 局部变量表,操作数栈,动态连接,方法返回地址 等。   每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。   通常所说的栈,一般是指虚拟机栈中的局部变量表部分。   局部变量表所需的内存在编译期间完成分配。   如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。    如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。 本地方法栈(线程私有):   和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。   也会抛出StackOverflowError和OutOfMemoryError。 Java堆(线程共享):

jvm系列(二):JVM内存结构

对着背影说爱祢 提交于 2019-12-18 04:25:32
所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障。 先看一张图,这张图能很清晰的说明JVM内存结构布局。 Java的内存结构: JVM内存结构主要有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配; 方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为java虚拟机栈和本地方法栈主要用于方法的执行。 在通过一张图来了解如何通过参数来控制各区域的内存大小 控制参数 -Xms设置堆的最小空间大小。 -Xmx设置堆的最大空间大小。 -XX:NewSize设置新生代最小空间大小。 -XX:MaxNewSize设置新生代最大空间大小。 -XX:PermSize设置永久代最小空间大小。 -XX:MaxPermSize设置永久代最大空间大小。 -Xss设置每个线程的堆栈大小。

关于jvm内存模型以及jvm内存结构划分

怎甘沉沦 提交于 2019-12-18 04:03:24
好久没有更新博客了 甚是怀念 网上看了很多资料都是对于两者概念比较模糊 首先关于JVM启动流程 * 接下来是JVM内存结构,是结构并不是内存模型 PC寄存器 每个线程拥有一个PC寄存器 在线程创建时 创建H 指向下一条指令的地址 执行本地方法时,PC的值为undefined 方法区 保存装载的类信息 类型的常量池 字段,方法信息 方法字节码 通常和永久区(Perm)关联在一起 但是基于JDK改动: JDK6时,String等常量信息置于方法 JDK7时,已经移动到了堆 Java堆 和程序开发密切相关 应用系统对象都保存在Java堆中 所有线程共享Java堆 对分代GC来说,堆也是分代的 Java栈 线程私有 栈由一系列帧组成(因此Java栈也叫做帧栈) 帧保存一个方法的局部变量、操作数栈、常量池指针 每一次方法调用创建一个帧,并压栈 ** 栈、堆、方法区交互 ** 具体代码体现: public class AppMain //运行时, jvm 把appmain的信息都放入方法区 { public static void main ( String [ ] args ) //main 方法本身放入方法区。 { Sample test1 = new Sample ( " 测试1 " ) ; //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面 Sample

JVM垃圾回收(三)

强颜欢笑 提交于 2019-12-18 03:09:50
一、对象是生是死 Java堆几乎存放着所有的对象实例,垃圾回收器回收垃圾前,需要判断哪些是存活的哪些是死去的。 引用计数器算法 :给对象添加一个引用计数器,当持有这个对象引用时,则计数器加一;当引用失效时,则计数器减一;当计数器为0的时候表示对象没有任何引用。这种算法不适合Java的垃圾回收器,因为无法解决对象间的互相引用。 可达性算法 :Java定义GC Root,作为引用链(Reference Chain)的依据,并指定哪些可作为GC Root如 java虚拟机栈中的局部变量表引用的对象、方法区的静态变量引用的对象、方法区的常量引用的对象、本地方法栈(Native方法)引用的对象、类加载器、Thread 。但仅仅定义引用和未引用太过于狭隘,因此在jdk1.2以后将引用划分为四种,分别是强引用( 强引用类似Object obj = new Object(),如果obj到GC Root可达则JVM永不会回收这对象 )、软引用(描述一些不是特别重要的对象,在JVM即将发生OOM异常时,对这些对象列入回收范围进行第二次回收,如果还是内存不足则会抛出OOM异常)、弱引用(描述哪些不重要的对象,相比于软引用,这些对象只会存活到下一次垃圾回收之前, eg:Map中存放key/value,如果某个key程序再也用不到,此时使用弱引用后将key=null,这样这个key就会被回收)和虚引用

Java的虚拟机内存模型

寵の児 提交于 2019-12-17 18:59:43
JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。 堆: 堆在虚拟机启动时就被创建,是用来存放对象的内存空间,几乎所有的对象都被放在堆中,这是一块线程共享的区域。 在规范中有这样一段描述: 所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配/标量替 换优化技术将会导致一些微妙的发生,所有的对象都分配在堆上也渐渐变得不是那么绝对了. java堆是垃圾回收机制主要场所,所以堆还可以细分为新生代,老年代,在细分的话就是新生代分为Eden空间/From Survivor空间/To

如何优雅的使用线程池

瘦欲@ 提交于 2019-12-17 17:43:31
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 线程池不仅在项目中是非常常用的一项技术而且在面试中基本上也是必问的知识点,接下来跟着我一起来巩固一下线程池的相关知识。在了解线程池之前我们先了解一下什么是 进程 什么是 线程 进程 程序:一般是一组CPU指令的集合构成的文件,静态存储在诸如硬盘之类的存储设备上 进程:当一个程序要被计算机运行时,就是在内存中产生该程序的一个运行时实例,我们就把这个实例叫做进程 用户下达运行程序的命令以后,就会产生一个进程,同一个程序可以产生多个进程(一对多的关系),以允许同时有多个用户运行同一个程序,却不会相冲突。 进程需要一些资源才能工作,如CPU的使用时间、存储器、文件、以及I/O设备,且为依序逐一执行,也就是每个CPU核心任何时间内仅能运行一项进程。但是在一个应用程序中一般不会是只有一个任务单条线执行下去,肯定会有多个任务,而创建进程又是耗费时间和资源的,称之为重量级操作。 创建进程占用资源太多 进程之间的通信需要数据在不同的内存空间传来传去,所以进程间通信会更加耗费时间和资源 线程 线程是操作系统能够进行运算调度的最小单位,大部分情况下它被包含在进程之中,是进程中实际的运作单位。一个进程可以并发多个线程,每个线程执行不同的任务。同一个进程中的多条线程共享该进程中的全部虚拟资源,例如虚拟地址空间、文件描述符、信号处理等等

Java 多线程之自旋锁

不羁的心 提交于 2019-12-17 15:17:08
一、什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成 busy-waiting 。 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。 二、Java如何实现自旋锁? 下面是个简单的例子: public class SpinLock { private AtomicReference<Thread> cas = new AtomicReference<Thread>(); public void lock() { Thread current = Thread.currentThread(); // 利用CAS while (!cas.compareAndSet(null,

java自旋锁

十年热恋 提交于 2019-12-17 14:49:39
什么是自旋锁? 自旋锁(spinlock) :是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。 Java如何实现自旋锁? 下面是个简单的例子: /** * Date: 2016年1月4日 下午4:41:50 * * @author medusar */ public class SpinLock { private AtomicReference cas = new AtomicReference(); public void lock() { Thread current = Thread.currentThread(); // 利用CAS while (!cas.compareAndSet(null, current)) { // DO nothing } } public void unlock() { Thread current = Thread.currentThread(); cas.compareAndSet(current, null); } } ock()方法利用的CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环,如果此时线程A没有释放锁

JVM运行时数据区域

最后都变了- 提交于 2019-12-17 14:16:25
运行时数据区域 定义 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域 类型 程序计数器 较小的内存空间,当前线程执行的字节 码的行号指示器;各线程之间独立存储,互不影响 虚拟机栈 每个线程私有的,线程在运行时,在执行每个方法的时候都会打包成一个栈帧,存储了局部变量表,操作数栈,动态链接,方法出口等信息,然后放入栈。每个时刻正在执行的当前方法就是虚拟机栈顶的栈桢。方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程。 栈桢大小缺省为1M,可用参数 –Xss调整大小,例如-Xss256k 堆 几乎所有对象都分配在这里,也是垃圾回收发生的主要区域,可用以下参数调整: -Xms:堆的最小值; -Xmx:堆的最大值; -Xmn:新生代的大小; -XX:NewSize;新生代最小值; -XX:MaxNewSize:新生代最大值; 例如- Xmx256m 方法区/永久代 用于存储已经被虚拟机加载的类信息,常量(“zdy”,"123"等),静态变量(static变量)等数据,可用以下参数调整: jdk1.7及以前:-XX:PermSize;-XX:MaxPermSize; jdk1.8以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize jdk1.8以后大小就只受本机总内存的限制 如:-XX:MaxMetaspaceSize=3M