最近的项目中,出现了内存和性能的问题,需要优化,所以趁着这个机会,把自己关于java虚拟机的东整理一下,不对的地方,欢迎指出。

数据类型,因为在java的优化的过程中,检测到的数据类型一般比较的基础,毕竟复杂的数据类型就是有基础的组合而来的。

Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,表示的是数据本身的值,是数据中的最基础的部分,一般包含:

byte,short,int,long,char,float,double,Boolean,returnAddress

其中的byte,short,int,long,char,float,double,Boolean 就不多说了,returnAddress 是会被Java虚拟机的jsr、ret和jsr_w指令所使用。return Address类型的值指向一条虚拟机指令的操作码。与前面的几种类型不同,returnAddress类型在Java语言之中并不存在相应的类型,也无法在程序运行期间更改returnAddress类型的值。

引用类型的变量保存引用的值,这个就是门牌,对应一个屋子,但是保存的是屋子的地址,也就是变量在内存中存储的首地址,一般包括:

类引用,接口引用,数组

堆和栈 这个比较的重要的概念,很有必要说一下。

程序运行的角度来说,一个程序能够运行起来,主要分为数据和逻辑,对应的就是堆和栈的对应关系。

栈,是程序运行时的逻辑存储的东西,比较标识方法的栈帧,表示程序运行时的单元。

堆,是程序运行时数据存储的地方,比如新建的对象,表示程序存储的单元。

栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;

堆解决的是数据存储的问题,即数据怎么放、放在哪儿。

在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享的。栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等组合而成的栈帧;而堆只负责存储对象信息。

为什么这么设计?当初设计的JVM规范的那些大牛,为什么会把这两者区分开,我们只能根据自己的推测,来猜想一二了。

① 符合面向对象的理念,把变化的和和不变得分离(总感觉有太极中阴阳的感觉),我们可以知道面向对象和面向过程的程序在执行上或者说针对需求的满足上面没有什么区别,但是面向对象的引用更加的贴近自然的思考方式。我们在编写程序的时候,仔细的想想能够知道我们编写的类的成员的变量,对象的属性就是存放在堆中,但是方法就是存储在栈中,这样我们在编写对应对象的数据结构的时候,实际上就是处理了数据和对应的逻辑,实现了太极中统一。仔细想想面向对象的这种设计比较的美。

② 从软件设计的角度讲:栈代表的处理逻辑,而堆代表的是处理的数据,这样就把处理什么,和怎么处理分开了,是的处理的逻辑更加的清晰,这种模块化的,隔离的思想在软件设计的方方面面都有体现。

③ 堆和栈的分离,不仅使栈对应的线程能够更好的关注自己的处理逻辑,还能够使堆中的内容可以被对多个栈共享,可以理解多个线程访问同一个对象,这种情况提供了一种有效的数据交互的方式,比如共享数据。另一方面也节约了空间,当然线程安全也是一个问题。

④ 栈因为运行的需要,需要保存运行时的上下文,需要进行地址段的划分,栈中对数据的引用只是一个内存的首地址,所以这样的话,堆中的对象就能够根据需要动态的增长。

堆和栈分离了,那么堆中存储的是什么,栈中存储的又是什么?

堆中存的是对象,栈中存储的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说可以动态变化的,但是栈中对应的只存了一个引用,4个byte,所以说java程序理论上面有实例数的限制。

为什么把基本类型放在栈中,一个原因是因为占有的空间小,本身占用的空间就小,放在堆中有需要加上四个字节的引用,划不来,再说基本类型的的长度是固定的,不会出现动态的增长。

现在基本类型和对象的引用都是存放在栈中,而且都是几个字节的一个数,因此在逻辑处理的时候,能够保持一致,但是基本类型和对象引用,对象本身是有区别的,这个时候对应的一个基本的问题是,java中参数的传递问题:

Java中的参数传递时传值呢?还是传引用?
要说明这个问题,先要明确两点:
     1. 不要试图与C进行类比,Java中没有指针的概念。

2. 程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。

因此java的方法的调用,都是传值调用,但是传引用调用的错觉是怎么造成的:

在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。所以这个修改是可以保持的了。

对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

这一段是摘抄自网上的,感觉说的比较的好。

java中,栈的大小可以通过-Xss来设置,当栈中存储的数据比较多时,可以适当的调大这个值,否则会出现 java.lang.stackoverflowerror的异常,常见的出现的异常是循环递归的情况。堆的大小可以通过-Xmx3/ –Xms设置,后面我们详细的说。

说完了存储的结构,再说一下一个java对象到底有多大?

基本的数据类型是固定的,就不说了,在java中,一个空的Object对象的大小是8byte,并且这个大小事保存堆中一个没有任何属性对象的大小,如果包括引用,也就是Object instance = new Object(); 就是12byte,其中的4byte就是引用所占的空间。

Class Student{

int nmber;

boolean isGood;

Object teacher;

}

大小为:8(空的Object) + 4(int的大小)+1(boolean的大小)+4(teacher引用的大小) = 17byte,因为java中对对象内存分配的时候都是以8的整数倍来分的,依次分配为24,这个对象的大小就是24byte。

另外关于引用的,就是java中引用的分类:

强引用,软引用,弱引用,虚引用

各个类别,就不详细说了,因为在优化的过程中,我们的代码一般采取的就是强引用,软引用和弱引用一般的在处理缓存的逻辑中用到。

JVM基础和调优(一)的更多相关文章

  1. JVM基础和调优(六)

    JVM设置过程中的一般的规范 在JVM的设置中,年轻代的设置比较的重要,因为年轻代存储空间分配的比较的块,可以说触发GC的机会比较的大. 默认的情况下:-XX:NewRatio  默认为2 说明:年轻 ...

  2. JVM基础和调优(四)

    垃圾回收算法中的一些问题 再上一遍中,说道JVM并不是采用一种垃圾回收的方法,因为不同的内存块采取的方法是不样的,那么:为什么要分块?为什么不采用同一种方法回收垃圾,这样不是更加的统一吗? 分块的垃圾 ...

  3. JVM基础和调优(二)

    主要讲述java虚拟机的内存体系结构 了解了JVM 的一些基础之后,我们来看看java虚拟机内存的体系结构,这个是理解JVM垃圾收集算法的前提,理解了内存结构我们才能够针对不同的部分根据我们的程序进行 ...

  4. JVM基础和调优(五)

    垃圾回收算法中收集器 接着上面的说,了解了JVM收集垃圾的过程,然后我们看一看收集器. 串行收集器:用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高.但是,也无法使用多处理器的优势,所 ...

  5. JVM基础和调优(三)

    主要讲解垃圾回收的算法 上面我们已经了解到了,JVM的体系的结构,这次我们来说一下垃圾回收的算法. 1. 最开始的想法,或者说垃圾回收的最容易想到的就是:引用计数(reference count) 我 ...

  6. Java系列笔记(4) - JVM监控与调优

    目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例     光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之.通过学习,我觉得JVM ...

  7. JVM监控与调优

    目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例     转:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html光说不练假把式,学习J ...

  8. [java] JVM监控与调优

    原文出处:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html   光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分 ...

  9. Tomcat性能调优-JVM监控与调优

    参数设置 在Java虚拟机的参数中,有3种表示方法用"ps -ef |grep "java"命令,可以得到当前Java进程的所有启动参数和配置参数: 标准参数(-),所有 ...

随机推荐

  1. for

    1,cout在显示bool值之前将他们转换为int,但cout.setf(ios::boolalpha)函数调用设置了一个标记,标记命令cout显示true 和 false 而不是 1 和0;

  2. Beanstalkd(ubuntu安装)

    安装Beanstalkd # apt-get install beanstalkd Unubtu 开启beanstalkd的持久化选项 #vim  /etc/default/beanstalkd 把S ...

  3. 实战:推断mysql中当前用户的连接数-分组筛选

    #connets.sh #!/bin/sh #ocpyang@126.com #依据输入參数u或d来显示出相应的username或数据库名中用户的连接数. #也能够输入u 详细username或d 详 ...

  4. C#Transfrom

    代码如下: private void btnConvertType_Click(object sender, EventArgs e) { if (rdo_btn_ConvertObject.Chec ...

  5. C语言之可重入函数 && 不可重入函数

    可重入函数 在 实时系统的设计中,经常会出现多个任务调用同一个函数的情况.如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他任 务调用这个函数的数据,从而导致不可预料 ...

  6. OrderAction

    package com.j1.mai.action; import java.io.BufferedReader; import java.io.IOException; import java.io ...

  7. 小学生之Java中的异常

    1.异常try{ //可能出现异常的代码}catch(Exception ex){ }finally{ //释放资源}2.异常的高级应用开闭原则:对修改关闭,对新增开放3.什么是异常?解析:异常是代码 ...

  8. DDD(Domain Driver Designer) 领域驱动设计简介

    领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity i ...

  9. Visual Studio 2015 RC Downloads

    https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs

  10. jQuery选择器 之详述

    jQuery选择器 一. 单词小计 Pervious 上一页sibling  同级first  第一last  最后not  不 Even  偶数    odd  奇数 header  页眉 一.jQ ...