记得刚大学毕业时,为了应付面试,疯狂的在网上刷JAVA的面试题,很多都靠死记硬背。其中有道面试题,给我的印象非常之深刻,有个大厂的面试官,顺着这道题目,一直往下问,问到java虚拟机的知识,最后把我给问住了。

我当时的表情是这样的:

后来我有机会面试别人了,也按照他的思路出面试题,很多已经工作了2年的程序员,结果也和我当年一样,都败在java虚拟机知识上。

我们先看面试题:

String str1 = "hello Alunbar";
String str2 = new String(str1);

会创建几个对象?

网上给出的解释是创建2个对象,str1对象在常量池中,str2对象在堆中。

下面是我和面试官的对话。

面试官:上面的代码创建了几个对象?

我:2个。

面试官:为什么是2个呢?

我:str1对象在常量池中,str2对象在堆中。用“=”等号创建String对象时,会先从字符串常量池中查找是否已经存在字符串对象,存在就直接返回引用地址,否则创建字符串对象并返回引用地址。

面试官:为什么会在常量池中创建字符串对象?

我:。。。我思考了半分钟,尴尬的回答不知道。

面试官:说说jvm虚拟机的内存结构。

我:。。。我再次面露难色,场面一度非常尴尬。

这次面试结束之后,我就回去疯狂查找资料,了解jvm虚拟机的相关知识。

这也是我的第一次面试,给我的印象非常之深刻。

下面我们来说说面试官的两个问题。

1、为什么会在常量池中创建字符串对象。

2、java虚拟机的内存结构。

先来看第一个问题。

为什么会在常量池中创建字符串对象?

字符串在所有编程语言中都是最常用的类型,其他的数据类型都可以转换为字符串类型,像int、long等基本数据类型和String都是可以互相转换的。为了提高字符串的使用效率,jvm虚拟机中特别开辟了一个常量池的内存空间,用于存储基本数据类型的对象,常量池中的对象是可以相互共享的,当然也包括了String。

我们一般将储存字符串的常量池成为字符串常量池。字符串常量池中会存在很多已经创建好的字符串对象,由于String类是用final修饰的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。

我们来看一段的代码:

String s1 = "Hello";
String s2 = "Hello";

这段代码只创建一个对象,s1和s2是同一个对象。根据上面的解读,java String s1 = "Hello"这行代码会先在字符串常量池查找Hello对象,没有发现,然后创建Hello对象并将引用返回给s1。java String s2 = "Hello"这行代码,也先去字符串常量池中查找Hello对象,发现已经存在,则直接返回给s2。因此s1和s2是同一个对象。

接着说说使用new创建字符串对象。

通过new创建字符串对象,会在堆中开辟一块新的内存空间,存储String字符串对象,因此使用new方式都会生成新的字符串对象,不管字符串的内容是否一致,使用new创建字符串时存在堆中,堆中的对象会被回收,而使用“=”创建字符串对象,是存放在常量池中,不会被回收,因此建议使用“=”的方式创建字符串对象,避免不必要的java对象创建和销毁的开销。

我们来看下面的创建字符串对象时的内存结构图:

s1和s2是通过“=”创建的字符串对象,它们的内存地址都一样,s3是使用new方式创建的字符串对象,s3和s1、s2的内存地址不一样。

现在接着看第二个问题。

java虚拟机的内存结构

虚拟机内存结构是一个很复杂的问题,这里只能讲一个大概,主要讲各个内存区域的作用。

java虚拟机由类加载器、运行时数据区和执行引擎构成。如下图所示:

平时我们说的java虚拟机内存结构,就是讲运行时数据区。

java虚拟机在执行java程序时,会将内存分为几个区域:程序计数器、方法区、虚拟机栈、本地方法栈、堆。

其中,方法区和堆是线程共享,程序计数器、虚拟机栈、本地方法栈时线程不共享。

1、程序计数器

只要学过汇编语言,对这个程序计数器都好理解,就是记录下一条将要执行的字节码指令。

通过操作系统知识我们知道启动一个程序时,就会创建一个进程,因此在执行java程序时,就会创建一个进程,java虚拟机就是一个进程。

一个进程中由多个线程组成,在任何一个时刻,java虚拟机只能执行一条线程中的指令。

java虚拟机通过读取某一个线程中的程序计数器决定该线程需要执行哪个基础功能,例如循环、读取数据库、跳转、异常处理、线程恢复等。

因此每个线程的程序计数器是相互独立,互不影响的。

2、java虚拟机栈

就是我们常说的java栈,在执行方法时,会在java栈中创建一个栈帧,用于存储局部变量表、操作数栈、方法出口等信息。

局部变量表中又会存放执行方法需要的boolean、char等各种基本数据类型,对象引用等。局部变量表大小在代码编译期间就已经确定。java栈也是线程私有。

创建线程时同步创建java栈,线程结束,java栈也同时销毁,释放占用的内存。

3、本地方法栈

和java虚拟机栈功能类似,有的虚拟机会将java虚拟机栈和本地方法栈合并。本地方法栈主要为虚拟机执行Native方法提供服务。

4、java堆

虚拟机中最大的一块内存区域,虚拟机启动时创建,主要用于存放对象实例,这块内存区域由所有线程共享。这个区域内的对象,可以被所有的线程访问。

这个区域也是java虚拟机重点管理的对象,当这块区域中的对象没有被引用,达到回收标准时,就会被java垃圾收集器回收,释放占用的内容空间。

java堆分为新生代和老年代,新生代又分为Eden空间、From Survivor空间和To Survivor空间。

使用new操作创建对象时,就会在这个区域开辟一块内存用于存储对象。

上面提到的java String str1 = new String("Hello")创建字符串,就会在java堆中开辟一块内存用于存储str1对象。

5、方法区

方法区主要存储被虚拟机加载的类信息、常量、静态变量等数据,我们也将这个内存区域称为永久代,这个区域不会进行内存回收。

方法区和java堆一样,所有线程共享。

方法区中包含一个运行时常量池,上面提到的java String str = "Hello"创建字符串,就是在运行时常量池中创建“Hello”对象。

小结:

1、两种创建字符串对象的差异。

2、java虚拟机内存区域的作用。

从一道面试题深入了解java虚拟机内存结构的更多相关文章

  1. JVM基础系列第6讲:Java 虚拟机内存结构

    看到这里,我相信大家对于一个 Java 源文件是如何变成字节码文件,以及字节码文件的含义已经非常清楚了.那么接下来就是让 Java 虚拟机运行字节码文件,从而得出我们最终想要的结果了.在这个过程中,J ...

  2. 深入剖析Java虚拟机内存结构

    深入剖析Java虚拟机内存模型 JVM整体架构 JVM整体架构如下: 通过编写代码来分析整个内存区域 public class Math { public static final Integer C ...

  3. Java虚拟机内存模型及垃圾回收监控调优

    Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存 ...

  4. Java程序猿从笨鸟到菜鸟之(九十二)深入java虚拟机(一)——java虚拟机底层结构具体解释

    本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 在曾经的博客里面,我们介绍了在java领域中大部分的知识点,从最基础的java最基本的语法 ...

  5. 如何设置Java虚拟机内存以适应大程序的装载

    Java虚拟机对于运行时的程序所占内存是有限制的,当我们的项目或者程序很大时,往往会照成内存溢出. 举个例子: public class SmallTest1 { public static void ...

  6. 打包apk java 虚拟机内存不足

    解决方案:在android->sdk->build-tools-android-version 中有个 dx.bat dx.bat --dex 命令的dx.bat脚本有这样一句代码 REM ...

  7. Java虚拟机-内存tips

    java虚拟机内存可以分为独占区和共享区. 独占区:虚拟内存栈.本地方法栈.程序计数器. 共享区:方法区.Java堆(用来存放对象实例). 程序计数器 比较小的内存空间,当前线程所执行的字节码的行号指 ...

  8. Java虚拟机内存溢出异常--《深入理解Java虚拟机》学习笔记及个人理解(三)

    Java虚拟机内存溢出异常--<深入理解Java虚拟机>学习笔记及个人理解(三) 书上P39 1. 堆内存溢出 不断地创建对象, 而且保证创建的这些对象不会被回收即可(让GC Root可达 ...

  9. java虚拟机内存不足,“Could not create the Java Virtual Machine”问题解决方案

    java虚拟机内存不足,"Could not create the Java Virtual Machine"问题解决方案 在运行java程序时,遇到问题"Could n ...

随机推荐

  1. JavaScript 数据结构与算法之美 - 线性表(数组、栈、队列、链表)

    前言 基础知识就像是一座大楼的地基,它决定了我们的技术高度. 我们应该多掌握一些可移值的技术或者再过十几年应该都不会过时的技术,数据结构与算法就是其中之一. 栈.队列.链表.堆 是数据结构与算法中的基 ...

  2. 初识JAVA语言

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321 前言        很多游戏开发者可能会有疑问,你会C#,JS,TS,为什么还要初识JAVA呢?有人可能会说,多学点对自己有好处 ...

  3. 【sybase】You can’t run SELECT INTO in this database的解决办法

    进入master 数据库,使用sp_dboption test ,'select into',true命令(其中test为要设置可用的数据库)

  4. 通过PHP与Python代码对比浅析语法差异

    一.背景 人工智能这几年一直都比较火,笔者一直想去学习一番:因为一直是从事PHP开发工作,对于Python接触并不算多,总是在关键时候面临着基础不牢,地动山摇的尴尬,比如在遇到稍微深入些的问题时候就容 ...

  5. P1963 [NOI2009]变换序列 倒叙跑匈牙利算法

    题意 构造一个字典序最小的序列T,使得 Dis(i, Ti) = di,其中i是从0开始的,Dis(x,y)=min{∣x−y∣,N−∣x−y∣} ,di由题目给定. 思路 二分图匹配,把左边的看成i ...

  6. P2746 [USACO5.3]校园网Network of Schools tarjan 缩点

    题意 给出一个有向图,A任务:求最少需要从几个点送入信息,使得信息可以通过有向图走遍每一个点B任务:求最少需要加入几条边,使得有向图是一个强联通分量 思路 任务A,比较好想,可以通过tarjan缩点, ...

  7. HDU 1848 Fibonacci again and again SG函数做博弈

    传送门 题意: 有三堆石子,双方轮流从某堆石子中去f个石子,直到不能取,问先手是否必胜,其中f为斐波那契数. 思路: 利用SG函数求解即可. /* * @Author: chenkexing * @D ...

  8. CF Edu54 E. Vasya and a Tree DFS+树状数组

    Vasya and a Tree 题意: 给定一棵树,对树有3e5的操作,每次操作为,把树上某个节点的不超过d的子节点都加上值x; 思路: 多开一个vector记录每个点上的操作.dfs这颗树,同时以 ...

  9. 牛客-2018多校算法第五场D-集合问题+并查集

    集合问题 题意: 给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足: 若x在集合A中,则a-x必须也在集合A中. 若x在集合B中,则b-x必须也在集合B中. 思路:并查集操作,自 ...

  10. ccpc网赛 hdu6705 path(队列模拟 贪心

    http://acm.hdu.edu.cn/showproblem.php?pid=6705 这是比赛前8题过的人数第二少的题,于是就来补了,但感觉并不难啊..(怕不是签到难度 题意:给个图,给几条路 ...