JVM基础和调优(一)
最近的项目中,出现了内存和性能的问题,需要优化,所以趁着这个机会,把自己关于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基础和调优(一)的更多相关文章
- JVM基础和调优(六)
JVM设置过程中的一般的规范 在JVM的设置中,年轻代的设置比较的重要,因为年轻代存储空间分配的比较的块,可以说触发GC的机会比较的大. 默认的情况下:-XX:NewRatio 默认为2 说明:年轻 ...
- JVM基础和调优(四)
垃圾回收算法中的一些问题 再上一遍中,说道JVM并不是采用一种垃圾回收的方法,因为不同的内存块采取的方法是不样的,那么:为什么要分块?为什么不采用同一种方法回收垃圾,这样不是更加的统一吗? 分块的垃圾 ...
- JVM基础和调优(二)
主要讲述java虚拟机的内存体系结构 了解了JVM 的一些基础之后,我们来看看java虚拟机内存的体系结构,这个是理解JVM垃圾收集算法的前提,理解了内存结构我们才能够针对不同的部分根据我们的程序进行 ...
- JVM基础和调优(五)
垃圾回收算法中收集器 接着上面的说,了解了JVM收集垃圾的过程,然后我们看一看收集器. 串行收集器:用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高.但是,也无法使用多处理器的优势,所 ...
- JVM基础和调优(三)
主要讲解垃圾回收的算法 上面我们已经了解到了,JVM的体系的结构,这次我们来说一下垃圾回收的算法. 1. 最开始的想法,或者说垃圾回收的最容易想到的就是:引用计数(reference count) 我 ...
- Java系列笔记(4) - JVM监控与调优
目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例 光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之.通过学习,我觉得JVM ...
- JVM监控与调优
目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例 转:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html光说不练假把式,学习J ...
- [java] JVM监控与调优
原文出处:http://www.cnblogs.com/zhguang/p/java-jvm-gc.html 光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分 ...
- Tomcat性能调优-JVM监控与调优
参数设置 在Java虚拟机的参数中,有3种表示方法用"ps -ef |grep "java"命令,可以得到当前Java进程的所有启动参数和配置参数: 标准参数(-),所有 ...
随机推荐
- Swift学习——A Swift Tour 函数
Functions and Closures 函数和封闭性(闭包) Functions 函数的使用 Swift中的函数定义和OC中有明显的差别了,使用func定义函数,在括号里定义參数和类型,用 ...
- Spring注解的使用和区别:@Component、@Service、@Repository、@Controller
Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository.@Service 和 @Controller.在目前的 Spring ...
- FusionChart实现金字塔分布图
1.XML提供数据源 Pyramid.xml: <?xml version="1.0" encoding="UTF-8"?> <chart m ...
- POJ 2502 Subway(迪杰斯特拉)
Subway Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6692 Accepted: 2177 Descriptio ...
- cocos2d-x v3.2 FlappyBird 各个类对象详细代码分析(7)
今天我们介绍最后两个类 GameOverLayer类 GameLayer类 GameLayer类是整个游戏中最重要的类,由于是整个游戏的中央系统,控制着各个类(层)之间的交互,这个类中实现了猪脚小鸟和 ...
- KindEditor简单的Demo使用
一般的做网站后台都会用到富文本编辑器,网上也有很多优秀的富文本编辑器,这里是开源中国的富文本编辑器推荐:http://www.oschina.net/project/tag/172/wysiwyg 我 ...
- C#。总结
数据类型--变量与常量--运算符与表达式--语句(if,for)--数组--函数--结构体一.数据类型: (一)内建类型 整型(int short long byte uint ushort ulon ...
- 纯js滑动脚本
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Android(通用机能)
数据存储 本地数据存在都是私有化的. 共享方法1是构造数据源组件.方法2将数据放入扩展存储设备. Mashup 服务组件默认没有运行在独立进程或线程中,因此费时操作一般需要起线程.可配置指定新进程. ...
- NSURLSessionDataTask
#import "ViewController.h" @interface ViewController ()<NSURLSessionDelegate,NSURLSessi ...