Java内存结构与模型

Python012

Java内存结构与模型,第1张

一 java内存结构

Heap(堆) 实例分配的地方 通过 Xms与 Xmx来设置

MethodArea(方法区域) 类的信息及静态变量 对应是Permanet Generation 通过 XX PermSize来设置

JavaStack(java的栈) 虚拟机只会直接对Javastack执行两种操作 以帧为单位的压栈或出栈 通过 Xss来设置 若不够会抛出StackOverflowError

ProgramCounter(程序计数器) 每一个线程都有它自己的PC寄存器 也是该线程启动时创建的 PC寄存器的内容总是指向下一条将被执行指令的饿地址 这里的地址可以是一个本地指针 也可以是在方法区中相对应于该方法起始指令的偏移量

Nativemethodstack(本地方法栈) 保存native方法进入区域的地址

当中Heap和MethodArea是被所有线程的共享使用的

而Javastack Programcounter和Nativemethodstack是以线程为粒度的 每个线程独自拥有自己的部分

二 内存模型

由以上可以知道java内存分为main memory和线程的Working Memory 就会涉及到这两种内存数据同步以及多个线程操作时数据一致性和可见性的问题 这就不可避免要加锁了 在java中可采用如下的形式

  synchronized关键字或使用ncurrent locks中的锁

  volatile关键字 Volatile表示的是线程每次操作都是在主内存中进行 这只能保证其可见性 而不能保证其的原子性 要有原子性还得加锁

  final变量(基本类型 类类型还是可以改值的)

三 如何保证线程安全

每个线程只操作自有的数据 这个可能性要小

设计的类无数据成员 也就没有共享变量 要有可用是 final或volatile

lishixinzhi/Article/program/Java/hx/201311/26489

方法如下:

首先

创建一个Bean用来存贮要得到的信

public class MonitorInfoBean {

/** 可使用内存. */

private long totalMemory

/** 剩余内存. */

private long freeMemory

/** 最大可使用内存. */

private long maxMemory

/** 操作系统. */

private String osName

/** 总的物理内存. */

private long totalMemorySize

/** 剩余的物理内存. */

private long freePhysicalMemorySize

/** 已使用的物理内存. */

private long usedMemory

/** 线程总数. */

private int totalThread

/** cpu使用率. */

private double cpuRatio

public long getFreeMemory() {

return freeMemory

}

public void setFreeMemory(long freeMemory) {

this.freeMemory = freeMemory

}

public long getFreePhysicalMemorySize() {

return freePhysicalMemorySize

}

public void setFreePhysicalMemorySize(long freePhysicalMemorySize) {

this.freePhysicalMemorySize = freePhysicalMemorySize

}

public long getMaxMemory() {

return maxMemory

}

public void setMaxMemory(long maxMemory) {

this.maxMemory = maxMemory

}

public String getOsName() {

return osName

}

public void setOsName(String osName) {

this.osName = osName

}

public long getTotalMemory() {

return totalMemory

}

public void setTotalMemory(long totalMemory) {

this.totalMemory = totalMemory

}

public long getTotalMemorySize() {

return totalMemorySize

}

public void setTotalMemorySize(long totalMemorySize) {

this.totalMemorySize = totalMemorySize

}

public int getTotalThread() {

return totalThread

}

public void setTotalThread(int totalThread) {

this.totalThread = totalThread

}

public long getUsedMemory() {

return usedMemory

}

public void setUsedMemory(long usedMemory) {

this.usedMemory = usedMemory

}

public double getCpuRatio() {

return cpuRatio

}

public void setCpuRatio(double cpuRatio) {

this.cpuRatio = cpuRatio

}

}

之后,建立bean的接口

public interface IMonitorService {

public MonitorInfoBean getMonitorInfoBean() throws Exception

}

然后,就是最关键的,得到cpu的利用率,已用内存,可用内存,最大内存等信息。

import java.io.InputStreamReader

import java.io.LineNumberReader

import sun.management.ManagementFactory

import com.sun.management.OperatingSystemMXBean

import java.io.*

import java.util.StringTokenizer

/**

* 获取系统信息的业务逻辑实现类.

* @author GuoHuang

*/

public class MonitorServiceImpl implements IMonitorService {

private static final int CPUTIME = 30

private static final int PERCENT = 100

private static final int FAULTLENGTH = 10

private static final File versionFile = new File("/proc/version")

private static String linuxVersion = null

/**

* 获得当前的监控对象.

* @return 返回构造好的监控对象

* @throws Exception

* @author GuoHuang

*/

public MonitorInfoBean getMonitorInfoBean() throws Exception {

int kb = 1024

// 可使用内存

long totalMemory = Runtime.getRuntime().totalMemory() / kb

// 剩余内存

long freeMemory = Runtime.getRuntime().freeMemory() / kb

// 最大可使用内存

long maxMemory = Runtime.getRuntime().maxMemory() / kb

OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory

.getOperatingSystemMXBean()

// 操作系统

String osName = System.getProperty("os.name")

// 总的物理内存

long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb

// 剩余的物理内存

long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize() / kb

// 已使用的物理内存

long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb

.getFreePhysicalMemorySize())

/ kb

// 获得线程总数

ThreadGroup parentThread

for (parentThread = Thread.currentThread().getThreadGroup()parentThread

.getParent() != nullparentThread = parentThread.getParent())

int totalThread = parentThread.activeCount()

double cpuRatio = 0

if (osName.toLowerCase().startsWith("windows")) {

cpuRatio = this.getCpuRatioForWindows()

}

else {

cpuRatio = this.getCpuRateForLinux()

}

// 构造返回对象

MonitorInfoBean infoBean = new MonitorInfoBean()

infoBean.setFreeMemory(freeMemory)

infoBean.setFreePhysicalMemorySize(freePhysicalMemorySize)

infoBean.setMaxMemory(maxMemory)

infoBean.setOsName(osName)

infoBean.setTotalMemory(totalMemory)

infoBean.setTotalMemorySize(totalMemorySize)

infoBean.setTotalThread(totalThread)

infoBean.setUsedMemory(usedMemory)

infoBean.setCpuRatio(cpuRatio)

return infoBean

}

private static double getCpuRateForLinux(){

InputStream is = null

InputStreamReader isr = null

BufferedReader brStat = null

StringTokenizer tokenStat = null

try{

System.out.println("Get usage rate of CUP , linux version: "+linuxVersion)

Process process = Runtime.getRuntime().exec("top -b -n 1")

is = process.getInputStream()

isr = new InputStreamReader(is)

brStat = new BufferedReader(isr)

if(linuxVersion.equals("2.4")){

brStat.readLine()

brStat.readLine()

brStat.readLine()

brStat.readLine()

tokenStat = new StringTokenizer(brStat.readLine())

tokenStat.nextToken()

tokenStat.nextToken()

String user = tokenStat.nextToken()

tokenStat.nextToken()

String system = tokenStat.nextToken()

tokenStat.nextToken()

String nice = tokenStat.nextToken()

System.out.println(user+" , "+system+" , "+nice)

user = user.substring(0,user.indexOf("%"))

system = system.substring(0,system.indexOf("%"))

nice = nice.substring(0,nice.indexOf("%"))

float userUsage = new Float(user).floatValue()

float systemUsage = new Float(system).floatValue()

float niceUsage = new Float(nice).floatValue()

return (userUsage+systemUsage+niceUsage)/100

}else{

brStat.readLine()

brStat.readLine()

tokenStat = new StringTokenizer(brStat.readLine())

tokenStat.nextToken()

tokenStat.nextToken()

tokenStat.nextToken()

tokenStat.nextToken()

tokenStat.nextToken()

tokenStat.nextToken()

tokenStat.nextToken()

String cpuUsage = tokenStat.nextToken()

System.out.println("CPU idle : "+cpuUsage)

Float usage = new Float(cpuUsage.substring(0,cpuUsage.indexOf("%")))

return (1-usage.floatValue()/100)

}

} catch(IOException ioe){

System.out.println(ioe.getMessage())

freeResource(is, isr, brStat)

return 1

} finally{

freeResource(is, isr, brStat)

}

}

1、java是如何管理内存的

Java的内存管理就是对象的分配和释放问题。(两部分)

分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。

释放 :对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。

2、 JVM的内存区域组成

java把内存分两种:一种是栈内存,另一种是堆内存1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;2。堆内存用来存放由new创建的对象和数组以及对象的实例变量 在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理

堆和栈的优缺点

堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。

缺点就是要在运行时动态分配内存,存取速度较慢; 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。

另外,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。