本地线程

JVM---内存结构

筅森魡賤 提交于 2019-12-16 00:23:47
程序计数器 Program Counter Register 是记住下一条JVM指令的执行地址 特点 是线程私有的 不会存在内存溢出 虚拟机栈 每个线程运行所需要的内存,成为虚拟机栈 每一个栈是由多个栈帧组成,栈帧是每个方法运行时需要的内存,一个栈帧对应着一个方法调用 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法 垃圾回收是否涉及栈内存? 不会,栈内存是一次次的方法调用产生的栈帧内存,而栈帧内存在方法调用完成后,会自动出栈。 栈内存分配越大越好吗? 通过参数-Xss size参数来指定栈的大小 栈内存如果分配的大,则可以执行的线程数,越来越少,因为物理内存是一定的。 方法内的局部变量是否是线程安全? 局部变量是线程私有的,所以是线程安全的 如果变量是多个共享的,则需要考虑线程安全问题 总结:如果方法内的局部变量没有逃离方法的作用范围,它是线程安全的 如果局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全 (引用作为参数,作为返回值) /** * 局部变量的线程安全问题 */ public class Demo1_17 { public static void main ( String [ ] args ) { StringBuilder sb = new StringBuilder ( ) ; sb . append ( 4 ) ; sb . append (

synchronized关键字

断了今生、忘了曾经 提交于 2019-12-15 22:50:09
synchronized关键字 一、语义 1、当线程释放锁时,JMM会把本地内存中的数据刷新到主内存中。 2、当获取锁时,会把本地内存设置为无效,从主内存中读取数据。 二、synchronized对象 对于synchronized的同步,锁是java中的对象。 1、对于实例方法,锁是当前对象的实例。 2、对于静态方法,锁是该类的Class对象。 3、对于同步代码块,锁是synchronized后面跟的对象。 JVM基于进入和退出monitor对象来实现synchronized代码块的。代码块同步是使用monitorenter 和monitorexit指令实现的。在java中,每一个对象都与一个minitor相对应。当且一个monitor被持有后,它处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。 三、JAVA对象头 1、如果java对象是一个数组,那么java对象头用三个字来表示 2、如果java对象不是数组,那么用两个字来表示 在32位虚拟机中,一个字长位32位。64位虚拟机中,一个字长是64位。 在java对象头中,第一个字为markword,默认存储对象的分代年龄,hashcode和锁标志位。其中的数据并会随着锁标志位的变化而变化。 第二个字即为CLass Metadata Address

【搞定Jvm面试】 Java 内存区域揭秘附常见面试题解析

北城余情 提交于 2019-12-15 13:48:16
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb (【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识)如果觉得不错的还,不妨去点个Star,鼓励一下! Java 内存区域详解 如果没有特殊说明,都是针对的是 HotSpot 虚拟机。 写在前面 (常见面试题) 基本问题 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针两种方式) 拓展问题 String 类和常量池 8 种基本类型的包装类和常量池 一 概述 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C++程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。 二 运行时数据区域 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK. 1.8 和之前的版本略有不同

JVM之运行时数据区域

帅比萌擦擦* 提交于 2019-12-15 04:45:07
1. JVM运行数据区域如下图所示: 1.1程序计数器 程序计数器占用很小的内存空间,用来看做当前线程执行的字节码的行号指示器,通过计数器的值来选取下一个需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器来完成。每个线程都有自己的程序计数器,也就是说它是线程私有的内存。 1.2虚拟机栈 虚拟机栈与程序计数器一样,也是线程私有的,占用内存也是很小一块,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的时候都会同时创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 局部变量表存放着编译器可知的8中基本数据类型(int、short、long、boolean、byte、double、float、char)、对象引用。 栈的生命周期很短随着线程或方法的开始而开始,随着线程或方法的结束而结束。 1.3本地方法栈 本地方法栈与虚拟机栈所发挥的作用非常相似,区别在于虚拟机栈是为虚拟机执行Java方法(字节码)服务,本地方法栈是为虚拟机使用Native方法服务(Native方法是用来调用非Java接口)。 1.4堆 堆是Java虚拟机中所管理的内存中最大的一块。Java堆是被线程共享的一块内存区域,在虚拟机启动的时创建

Java中Volatile关键字详解

我的未来我决定 提交于 2019-12-15 02:08:50
一、基本概念 先补充一下概念:Java 内存模型中的可见性、原子性和有序性。 可见性:   可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。    可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。 也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。   在 Java 中 volatile、synchronized 和 final 实现可见性。 原子性:    原子是世界上的最小单位,具有不可分割性。 比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作

Java并发:volatile内存可见性和指令重排

隐身守侯 提交于 2019-12-15 00:34:23
volatile两大作用 1、保证内存可见性 2、防止指令重排 此外需注意volatile 并不保证操作的原子性。 (一)内存可见性 1 概念 JVM内存模型:主内存和线程独立的工作内存 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存(比如CPU的寄存器),线程只能访问自己的工作内存,不可以访问其它线程的工作内存。 工作内存中保存了主内存共享变量的 副本 ,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。 如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,定义了8种原子操作: (1) lock:将主内存中的变量锁定,为一个线程所独占 (2) unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量 (3) read:将主内存中的变量值读到工作内存当中 (4) load:将read读取的值保存到工作内存中的变量副本中。 (5) use:将值传递给线程的代码执行引擎 (6) assign:将执行引擎处理返回的值重新赋值给变量副本 (7) store:将变量副本的值存储到主内存中。 (8) write:将store存储的值写入到主内存的共享变量当中。 通过上面Java内存模型的概述,我们会注意到这么一个问题

1.JVM前奏篇(看官网怎么说)

£可爱£侵袭症+ 提交于 2019-12-14 19:05:25
JVM( Java Virtual Machine ) 前奏篇(看官网规范怎么说) 1.The relation of JDK/JRE/JVM 在下图中,我们所接触的,最熟悉,也是经常打交道的 最顶层 Java Language (.java 文件所写的内容),也就是java 语法层面。官方 划定出了 JDK(Java SE Development Kit (JDK) 8),JRE(Java SE Runtime Environment (JRE) 8) 所包含的Java components。 官网 这里去。 官方描述二者关系:     JDK 8 is a superset of JRE 8, and contains everything that is in JRE 8, plus tools such as the compilers and debuggers necessary for developing applets and applications. JRE 8 provides the libraries, the Java Virtual Machine (JVM), and other components to run applets and applications written in the Java programming language.

Java内存管理-JVM内存模型以及JDK7和JDK8内存模型对比总结(三)

随声附和 提交于 2019-12-14 17:37:47
转载:https://www.jianshu.com/p/5b3717ff06ce 知识地图: 一、概述 Java的内存管理采用[自动内存管理]机制,因为这个自动管理机制,Java程序员就不需要去写释放内存的代码,而且不容易出现内存泄漏问题(比C/C++程序员少一些烦恼)。但是由于内存的申请和释放都交给了Java虚拟机,一旦出现内存泄漏和溢出问题时,在不了解Java虚拟机内存结构和自动管理机制的情况下,就很难排查问题的所在。所以如果想要成为一个优秀的程序员或者进阶为一个牛逼的架构师,掌握Java虚拟机的自动内存管理机制那是必须的。 二、JVM运行时数据区域 根据《Java虚拟机规范(Java SE 7版)》的规定,Java虚拟机所管理的内存将会包括以下几个运行时的数据区域:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。 如图所示: 注:上图的虚拟机运行时数据区是Java虚拟机规范所规定的区域,不同的虚拟机有不同的实现。 上面图片有线程共享和线程隔离的区域,下面在通过一张图片来进行简单说明,让你更加清晰的理解什么是线程共享和什么是线程隔离。 通过上面的两个图,大概对JVM的内存模型有个初步的认识

java虚拟机

百般思念 提交于 2019-12-14 02:46:22
目录(java虚拟机) 一、虚拟机 ​ 同样的java代码在不同平台生成的机器码肯定是不一样的,因为不同的操作系统底层的硬件指令集是不同的。 同一个java代码在windows上生成的机器码可能是0101…,在linux上生成的可能是1100…,那么这是怎么实现的呢? 不知道同学们还记不记得,在下载jdk的时候,我们在oracle官网,基于不同的操作系统或者位数版本要下载不同的jdk版本,也就是说针对不同的操作系统,jdk虚拟机有不同的实现。 那么虚拟机又是什么东西呢,如图是从软件层面屏蔽不同操作系统在底层硬件与指令上的区别,也就是跨平台的由来。 说到这里同学们可能还是有点不太明白,说的还是太宏观了,那我们来了解下java虚拟机的组成。 二、虚拟机组成 ​ 1.栈 我们先讲一下其中的一块内存区域栈,大家都知道栈是存储局部变量的,也是线程独有的区域,也就是每一个线程都会有自己独立的栈区域。 public class Math { public static int initData = 666; public static User user = new User(); public int compute() { int a = 1; int b = 2; int c = (a+b) * 10; return c; } public static void main(String[

Java并发之volatile关键字

筅森魡賤 提交于 2019-12-13 23:49:49
引言 说到多线程,我觉得我们最重要的是要理解一个临界区概念。 举个例子,一个班上1个女孩子(临界区),49个男孩子(线程),男孩子的目标就是这一个女孩子,就是会有竞争关系(线程安全问题)。推广到实际场景,例如对一个数相加或者相减等等情形,因为操作对象就只有一个,在多线程环境下,就会产生线程安全问题。理解临界区概念,我们对多线程问题可以有一个好意识。 Jav内存模型(JMM) 谈到多线程就应该了解一下Java内存模型(JMM)的抽象示意图.下图: 线程A和线程B执行的是时候,会去读取共享变量(临界区),然后各自拷贝一份回到自己的本地内存,执行后续操作。 JMM模型是一种规范,就像Java的接口一样。JMM会涉及到三个问题:原子性,可见性,有序性。 所谓原子性。就是说一个线程的执行会不会被其他线程影响的。他是不可中断的。举个例子: int i=1 这个语句在Jmm中就是原子性的。无论是一个线程执行还是多个线程执行这个语句,读出来的i就是等于1。那什么是非原子性呢,按道理如果Java的代码都是原子性,应该就不会有线程问题了啊。其实JMM这是规定某些语句是原子性罢了。举个非原子性例子: i ++; 这个操作就不是原子性的了。因为他就是包含了三个操作:第一读取i的值,第二将i加上1,第三将结果赋值回来给i,更新i的值。 所谓可见性。可见性表示如果一个值在线程A修改了