精华内容
下载资源
问答
  • 查看JAVA进程占用内存

    万次阅读 2019-04-10 21:57:33
    使用ps查看JAVA进程使用的内存和虚拟内存( Linux内存管理 ): $ ps -p ${pid} -o rss,vsz RSS VSZ 7152568 17485844 VSZ是虚拟内存,RSS是实际使用的内存,单位KB。你会发现,RSS会远远超过了-Xmx的设定。 为什么...

      使用ps查看JAVA进程使用的内存和虚拟内存( Linux内存管理 ):

    $ ps -p ${pid} -o rss,vsz  
    RSS     VSZ
    7152568 17485844
    

      VSZ是虚拟内存,RSS是实际使用的内存,单位KB。你会发现,RSS会远远超过了-Xmx的设定。

      为什么呢?首先要搞清楚JVM的内存机制: JVM内存区域总体分两类,heap区 和 非heap 区(本地内存) 。

    • heap区: 堆区分为Young Gen,Old Gen。
    • 非heap区: Code Cache(代码缓存区)、Perm Gen(永久代)、Jvm Stack(java虚拟机栈)、Local Method Statck(本地方法栈)。

      这样,大概懂了吧。-Xmx设定的仅仅只是heap区。
      
      
      JDK1.8有Native Memory Tracker也可以帮助定位内存。NMT必须先通过VM启动参数中打开,不过要注意的是,打开NMT会带来5%-10%的性能损耗。
    -XX:NativeMemoryTracking=[off | summary | detail]

    off: 默认关闭
    summary: 只统计各个分类的内存使用情况.
    detail: Collect memory usage by individual call sites.

      一般在启动参数上加入-XX:NativeMemoryTracking=detail,然后通过jcmd查看NMT报告以及查看对比情况。
    jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

    summary: 分类内存使用情况.
    detail: 详细内存使用情况,除了summary信息之外还包含了虚拟内存使用情况。
    baseline: 创建内存使用快照,方便和后面做对比
    summary.diff: 和上一次baseline的summary对比
    detail.diff: 和上一次baseline的detail对比
    shutdown: 关闭NMT

      其中scale参数可以指定展示的单位,可以为KB或者MB或者GB

    $ jcmd ${pid} VM.native_memory summary
    
    Total: reserved=8491110KB, committed=7220750KB
    -                 Java Heap (reserved=6293504KB, committed=6291456KB) 
                                (mmap: reserved=6293504KB, committed=6291456KB) 
     
    -                     Class (reserved=1107429KB, committed=66189KB) 
                                (classes #11979)
                                (malloc=1509KB #18708) 
                                (mmap: reserved=1105920KB, committed=64680KB) 
     
    -                    Thread (reserved=159383KB, committed=159383KB) 
                                (thread #156)
                                (stack: reserved=158720KB, committed=158720KB)
                                (malloc=482KB #788) 
                                (arena=182KB #310)
     
    -                      Code (reserved=255862KB, committed=41078KB) 
                                (malloc=6262KB #9319) 
                                (mmap: reserved=249600KB, committed=34816KB) 
     
    -                        GC (reserved=449225KB, committed=449225KB) 
                                (malloc=166601KB #1714646) 
                                (mmap: reserved=282624KB, committed=282624KB) 
     
    -                  Compiler (reserved=395KB, committed=395KB) 
                                (malloc=265KB #856) 
                                (arena=131KB #3)
     
    -                  Internal (reserved=146041KB, committed=146041KB) 
                                (malloc=132185KB #276370) 
                                (mmap: reserved=13856KB, committed=13856KB) 
     
    -                    Symbol (reserved=31487KB, committed=31487KB) 
                                (malloc=29209KB #91080) 
                                (arena=2278KB #1)
     
    -    Native Memory Tracking (reserved=33212KB, committed=33212KB) 
                                (malloc=168KB #2575) 
                                (tracking overhead=33044KB)
     
    -               Arena Chunk (reserved=2284KB, committed=2284KB)
                                (malloc=2284KB) 
     
    -                   Unknown (reserved=12288KB, committed=0KB)
                                (mmap: reserved=12288KB, committed=0KB) 
     
    
    COLLECTOR_PID=`ps -ef|grep "ProcessName" | grep -v grep | awk '{print $2}'`
    OUTDIR=/opt/chkmem
    HOSTNAME=`hostname`
    
    prstat -s rss 1 1 > ${OUTDIR}/${HOSTNAME}_coll_${COLLECTOR_PID}_prstat_`date '+%Y%m%d_%H%M%S'`.txt
    
    /opt/jdk1.8.0_40/bin/jcmd ${COLLECTOR_PID} VM.native_memory detail > ${OUTDIR}/${HOSTNAME}_coll_${COLLECTOR_PID}_nmd_`date '+%Y%m%d_%H%M%S'`.txt
    
    pmap -x ${COLLECTOR_PID} > ${OUTDIR}/${HOSTNAME}_coll_${COLLECTOR_PID}_pmap_`date '+%Y%m%d_%H%M%S'`.txt
    
    展开全文
  • java堆内存和栈内存的区别

    千次阅读 2015-11-03 14:05:48
    一段时间之前,我写了两篇文章文章分别是Java的垃圾回收和Java的值传递,从那之后我收到了很多要求解释Java堆内存和栈内存的邮件,并且要求解释他们的异同点。在Java中你会看到很多堆和栈内存的引用,JavaEE书和文章...

    一段时间之前,我写了两篇文章文章分别是Java的垃圾回收和Java的值传递,从那之后我收到了很多要求解释Java堆内存和栈内存的邮件,并且要求解释他们的异同点。

    在Java中你会看到很多堆和栈内存的引用,JavaEE书和文章很难在程序的角度完全解释什么是堆什么是栈。

    Java堆内存

    堆内存在Java运行时被使用来为对象和JRE类分配内存。不论什么时候我们创建了对象,它将一直会在堆内存上创建。垃圾回收运行在堆内存上来释放没有任何引用的对象所占的内存,任何在堆上被创建的对象都有一个全局的访问,并且可以在应用的任何位置被引用。

    Java栈内存

    Java的栈内存被用来线程的执行,他们包含生命周期很短的具体值的方法和在堆中使用这个方法对象的引用。栈内存是LIFO(后进先出)序列。当方法被调用的时候,堆内存中一个新的块被创建,保存了本地原始值和在方法中对其他对象的引用。这个方法结束之后,这个块对其他方法就变成可用的了。栈内存与堆内存相比是非常小的。
    我们用下边的例子理解堆内存和栈内存
    package com.journaldev.test;
     
    public class Memory {
     
        public static void main(String[] args) { // Line 1
            int i=1; // Line 2
            Object obj = new Object(); // Line 3
            Memory mem = new Memory(); // Line 4
            mem.foo(obj); // Line 5
        } // Line 9
     
        private void foo(Object param) { // Line 6
            String str = param.toString();  Line 7
            System.out.println(str);
        } // Line 8
     
    }

    下边的图片展示了上边程序堆和栈内存的引用,并且是怎么用来存储原始值、对象和变量的引用。
     
    我们来看看程序执行的过程:
    1、只要我们一运行这个程序,它会加载所有的运行类到堆内存中去,当在第一行找到main()方法的时候,Java创建可以被main()方法线程使用的栈内存。
    2、当在第一行,我们创建了本地原始变量,它在main()的栈中创建和保存。
    3、因为我们在第三行创建了对象,它在堆内存中被创建,在栈内存中保存了它的引用,同样的过程也发生在第四行我们创建Memory对象的时候。
    4、当在第五行我们调用foo()方法的时候,在堆的顶部创建了一个块来被foo()方法使用,因为Java是值传递的,在第六行一个新的对象的引用在foo()方法中的栈中被创建
    5、在第七行一个String被创建,它在堆空间中的 String池中运行,并且它的引用也在foo()方法的栈空间中被创建
    6、foo()方法在第八行结束,此时在堆中为foo()方法分配的内存块可以被释放
    7、在第九行,main()方法结束,栈为main()方法创建的内存空间可以被销毁。同样程序也在行结束,Java释放了所有的内存,结束了程序的运行

    堆内存和栈内存的区别

    基于上边的解释我们可以很简单的总结出堆和栈的区别:
    1、应用程序所有的部分都使用堆内存,然后栈内存通过一个线程运行来使用。
    2、不论对象什么时候创建,他都会存储在堆内存中,栈内存包含它的引用。栈内存只包含本地原始变量和堆中对象变量的引用。
    3、存储在堆中的对象是全局可以被访问的,然而栈内存不能被其他线程所访问。
    4、栈中的内存管理使用LIFO的方式完成,而堆内存的管理要更复杂了,因为它是全局被访问的。堆内存被分为,年轻一代,老一代等等,更多的细节请看, 这篇文章
    5、栈内存是生命周期很短的,然而堆内存的生命周期从程序的运行开始到运行结束。
    6、我们可以使用-Xms和-Xmx JVM选项定义开始的大小和堆内存的最大值,我们可以使用-Xss定义栈的大小
    7、当栈内存满的时候,Java抛出java.lang.StackOverFlowError异常而堆内存满的时候抛出java.lang.OutOfMemoryError: Java Heap Space错误
    8、和堆内存比,栈内存要小的多,因为明确使用了内存分配规则(LIFO),和堆内存相比栈内存非常快。
     

    原文地址:http://www.journaldev.com/4098/java-heap-memory-vs-stack-memory-difference

    关注我,获取400个的赚钱金点子,轻松开启程序员的副业生涯

     

    展开全文
  • 内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。 使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,代码中能直接操作...
    1. 堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。
    2. 使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,代码中能直接操作本地内存的方式有2种:使用未公开的Unsafe和NIO包下ByteBuffer。

    堆外内存的好处是:

    1、可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间。
    2、理论上能减少GC暂停时间。
    3、可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现。
    4、它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据。

    堆外内存优点:

    堆外内存,其实就是不受JVM控制的内存。相比于堆内内存有几个优势:
      1 减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作(可能使用多线程或者时间片的方式,根本感觉不到)
      2 加快了复制的速度。因为堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。

    堆外内存缺点:

    而福之祸所依,自然也有不好的一面:
      1 堆外内存难以控制,如果内存泄漏,那么很难排查
      2 堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合。

    java的堆栈内存

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存

    在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
    堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。
    引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

    java中内存分配策略及堆和栈的比较

      1 内存分配策略
      按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
      静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.
      栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。
      静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.

      2 堆和栈的比较
      上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:
      从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:
      在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个”大小多少”是在编译时确定的,不是在运行时.
      堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).

      3 JVM中的堆和栈
      JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。
      我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的.
      从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。
      每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
      
      

    Java 中的堆和栈

      Java把内存划分成两种:一种是栈内存,一种是堆内存。
      在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
      当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
      堆内存用来存放由new创建的对象和数组。
      在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
      在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。
      引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。
      具体的说:
      栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
      Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
      栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。
      栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
      int a = 3;
      int b = 3;
      编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量 。

    展开全文
  •  1.jps 获取Java进程的PID。  2.jstack pid >> java.txt 导出CPU占用高进程的线程。  3.top -H -p PID 查看对应进程的哪个线程占用CPU过高。  4.echo “obase=16; PID” | bc 将线程的PID转换为16进制。 ...
  • JAVA之堆内存和栈内存的区别

    千次阅读 2018-01-25 12:30:45
    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过...

    转自http://blog.csdn.net/as02446418/article/details/47007975
    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存

    在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
    堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。
    引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

    java中内存分配策略及堆和栈的比较

      1 内存分配策略

      按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.

      静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.

      栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。

      静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.

      2 堆和栈的比较

      上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:

      从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:

      在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个”大小多少”是在编译时确定的,不是在运行时.

      堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).

      3 JVM中的堆和栈

      JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

      我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的.

      从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。

      每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。

      Java 中的堆和栈

      Java把内存划分成两种:一种是栈内存,一种是堆内存。

      在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。

      当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。

      堆内存用来存放由new创建的对象和数组。

      在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。

      在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。

      引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

      具体的说:

      栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

      Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

      栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。

      栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

     int a = 3;

      int b = 3;
    1
    2
    3
      编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量

    展开全文
  • java栈内存不足

    千次阅读 2015-04-20 23:18:31
    前置条件:使用命令java -Xmx1g -Xms1g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:...
  • Java知识体系最强总结(2021版)

    万次阅读 多人点赞 2019-12-18 10:09:56
    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同...
  • 首先看一下一个java进程的jmap输出:  代码如下   [lex@chou ~]$ jmap -heap 837 Attaching to process ID 837, please wait... Debugger attached successfully. Server compiler detected. JVM
  • 查看Java进程的堆内存: [root@~]# jmap -heap 21945 Attaching to process ID 21945, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.131-b11 using ...
  • 在docker中 java进程内存设置

    千次阅读 2020-08-19 21:32:34
    微服务和docker的结合应该是现在服务端的主流技术,随着springboot的出现,有很多公司已经把微服务迁移到了docker容器中,我们也不甘寂寞,也尝试...后来由于java默认使用的内存是docker实体机器1/4的内存,导致部署了
  • 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存...
  • Java进程使用的虚拟内存确实比Java Heap要大很多。JVM包括很多子系统:垃圾收集器、类加载系统、JIT编译器等等,这些子系统各自都需要一定数量的RAM才能正常工作。 当一个Java进程运行时,也不仅仅是JVM在消耗RAM,...
  • 很多时候,我们运行的Java程序并没有设定堆的内存限制参数,正常来说可以有两个参数来指定初始分配的堆内存和堆内存的最大值,分别为: -Xmx 用来设置你的应用程序(不是JVM)能够使用的最大内存数(相当于 -XX:...
  • Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当...
  • java堆内存与栈内存

    千次阅读 2017-10-03 17:11:33
    java堆内存与栈内存Java把内存分成两种,一种叫做栈内存,一种叫做堆内存在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配...
  • JAVA内存泄漏,内存溢出,溢出

    千次阅读 2019-06-04 21:43:29
    3 Java内存回收机制 4 Java内存泄露引起原因 4.1 静态集合类引起内存泄露 4.2 监听器 4.3 各种连接 4.4 单例模式 1 定义 内存溢出 (out of memory),是指程序在申请内存时,没有足够的内存空间供其使用,...
  • JVM栈内存设置

    千次阅读 2018-01-12 10:44:03
    Java程序中,每个线程都有自己的Stack Space()。这个Stack Space不是来自Heap的分配。所以Stack Space的大小不会受到-Xmx和-Xms的影响,这2个JVM参数仅仅是影响Heap的大小。 Stack Space用来做方法的递归调用...
  • Java虚拟机内存模型

    万次阅读 多人点赞 2021-02-18 15:08:57
    1、结合字节码指令理解Java虚拟机和栈帧 栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间。 每个栈帧中包括局部变量表(Local Variables)、操作数(Operand Stack)、指向运行时常量池的引用...
  • 主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。 jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,...
  • java 进程占用系统内存过高分析

    千次阅读 2020-03-09 15:57:26
    JVM的内存 先放一张JVM的内存划分图,...那么一个Java进程最大占用的物理内存为: Max Memory = eden + survivor + old + String Constant Pool + Code cache + compressed class space + Metaspace + Thread st...
  • 为什么设置-Xmx4g但是java进程内存占用达到8g?

    千次阅读 热门讨论 2021-01-28 16:05:06
    前言 不知道大家在开发过程中有没有遇到过类似的问题,明明通过JVM参数-...2.通过ps查看java进程 项目启动命令为: java -Xmx6g -Xms6g - -XX:+UseG1GC -jar /home/pgcp/pgcp-0.0.1-SNAPSHOT.jar 3.通过top命令查看
  • java堆内存、栈内存、方法区

    千次阅读 2017-03-02 16:58:43
    JAVA的JVM的内存可分为3个区:堆(heap)、(stack)和方法区(method) 堆区: 1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) 2.jvm只有一个堆区(heap)被所有线程共享...
  • JAVA 查看线程、内存

    千次阅读 2019-09-10 10:51:51
    与linux上的ps类似,用来显示本地的java进程,并显示他们的进程ID jconsole:一个java GUI监视工具 可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。 命令行内输入 jconsole, 会弹出下图所示...
  • 4种方式配置不同作用域的jvm的堆栈内存! 1、Eclise 中设置jvm内存: 修改eclipse的配置文件,对所有工程都起作用  修改eclipse根目录下的eclipse.ini文件  -vmargs //虚拟机设置  -Xms40m //初始内存  -Xmx...
  • 很多人的理解是,Java进程占用的内存就是堆内存占用,再进一步就是Perm/元数据区的占用。 Java面试宝典里的,大多点到这为止,其实真实情况远远不是这样的。 如果持有以上观点,那么服务器上出现OOM,一点儿也不奇怪...
  • 堆内存和栈内存的区别

    万次阅读 2019-03-14 00:03:46
    总结: 1 栈:为编译器自动分配和释放,如函数参数、局部变量、临时变量等等 2 堆:为成员分配和释放,由程序员自己申请、自己释放。否则发生内存泄露。...栈内存和堆内存的区别(一个笔试题的一部分)http://...
  • 一、Linux如何定位java进程占用系统资源使用率高的问题(简单实现) linux文件夹下先创建一个TheradDemo.java 文件,明显会在10行死循环,此时会大量占用cpu的资源。下面通过linux命令来定位这个问题 import java....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 108,330
精华内容 43,332
关键字:

java进程的栈内存如何查看

java 订阅