异常/深入java.lang.Throwable

11 条评论

2017 年 01 月 06 日 at 下午 10:03分类:java

在java语言中,错误类的基类是java.lang.Error,异常类的基类是java.lang.Exception。

相同点:java.lang.Error和java.lang.Exception都是java.lang.Throwable的子类,因此java.lang.Error和java.lang.Exception自身及其子类都可以作为throw的使用对象,如:throw new MyError();和throw new MyException();其中,MyError类是java.lang.Error的子类,MyException类是java.lang.Exception的子类。

不同点:java.lang.Error自身及其子类不需要try-catch语句的支持,可在任何时候将返回方法,如下面的方法定义:
public String myMethod() {
throw new MyError();
}
其中MyError类是java.lang.Error类的子类。

java.lang.Exception自身及其子类需要try-catch语句的支持,如下的方法定义是错误的:
public String myMethod() {
throw new MyException();
}
正确的方法定义如下:
public String myMethod() throws MyException {
throw new MyException();
}
其中MyException类是java.lang.Exception的子类。

—————————————-
1)如果代码中有一个地方发生了异常, 也就是Throwable被new出来的那个地方,由于Throwable的构造函数中直接调用了fillInStackTrace(), 那么Throwable会一步一步地追踪方法的调用,直到追踪到线程的终端, 例如,main线程的main()方法,其他的线程的run()方法。
2)fillInStackTrace是native方法,也只有native方法可以完成这样的代码追踪。
3)Throwable有一个方法setStackTrace()之外(注意到setStackTrace只是use by RPC frameworks and other advanced systems),也就是说setStackTrace()通常不会被应用程序用到。
4)跟setStackTrace()相反,StackTrace中的信息可以通过调用fillInStackTrace()方法来获得,此外还可以通过deserialize的方法来获得;可以看看它的writeObject()方法。
5)fillInStackTrace()方法返回的Throwable为this指针; 这样可以很方便的使用throw ex.fillInStackTrace();
——————————————–
异常是当JVM(JAVA虚拟机)在执行应用程序的某个方法的时候遇到的非正常现象,JVM就会生成一个异常对象,抛给客户以便客户进行异常处理.Struts框架的异常处理机制建立在java异常处理的基础之上.在研究Struts异常处理之前,先回顾一下java异常处理原理,理解java虚拟机JVM的异常处理过程有助于应用设计正确的异常处理方法.处理异常需要JVM付出不小的开销,所以用于必须慎重使用.

JAVA异常是在java程序运行的时候遇到非正常的情况而创建的对象,它封装了异常信息,java异常的根类为java.lang.Throwable,整个类有两个直接子类java.lang.Error和java.lang.Exception.Error是程序本身无法恢复的严重错误.Exception则表示可以被程序捕获并处理的异常错误.JVM用方法调用栈来跟踪每个线程中一系列的方法调用过程,该栈保存了每个调用方法的本地信息.对于独立的JAVA程序,可以一直到该程序的main方法.当一个新方法被调用的时候,JVM把描述该方法的栈结构置入栈顶,位于栈顶的方法为正确执行的方法.当一个JAVA方法正常执行完毕,JVM回从调用栈中弹处该方法的栈结构,然后继续处理前一个方法.如果java方法在执行代码的过程中抛出异常,JVM必须找到能捕获异常的catch块代码.它首先查看当前方法是否贼这样的catch代码块,如果存在就执行该catch代码块,否则JVM回调用栈中弹处该方法的栈结构,继续到前一个方法中查找合适的catch代码块.最后如果JVM向上追到了main()方法,也就是一直把异常抛给了main()方法,仍然没有找到该异常处理的代码块,该线程就会异常终止,如果该线程是主线程,应用程序也随之终止,此时JVM将把异常直接抛给用户,在用户终端上会看到原始的异常信息.

Java虚拟机的堆、栈、堆栈如何去理解

14 条评论

2017 年 01 月 02 日 at 下午 5:25分类:java

java内存是分为堆,栈和方法区。

堆中分配的是对象,也就是new出来的东西。

栈中分配的是基本类型和自定义对象的引用。

方法区存放的是类信息和static变量。

比如说你在方法里有一个String a=new String(“123″),就会先在堆里创建一个“123”的对象,然后再把这个对象的引用放到栈里面。

再举个栗子(别的地方找的):

对于一个方法

public void Method1()
{
int i = 4;
int y = 2;
class1 cls1 = new class1();
}

 

https://www.zhihu.com/question/29833675

Xms Xmx PermSize MaxPermSize 区别

11 条评论

2016 年 12 月 10 日 at 下午 6:01分类:java

Eclipse崩溃,错误提示:
MyEclipse has detected that less than 5% of the 64MB of Perm
Gen (Non-heap memory) space remains. It is strongly recommended
that you exit and restart MyEclipse with new virtual machine memory
paramters to increase this memory.   Failure to do so can result in
data loss. The recommended Eclipse memory parameters are:
eclipse.exe -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M

1.参数的含义
-vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M
-vmargs 说明后面是VM的参数,所以后面的其实都是JVM的参数了
-Xms128m JVM初始分配的堆内存
-Xmx512m JVM最大允许分配的堆内存,按需分配
-XX:PermSize=64M JVM初始分配的非堆内存
-XX:MaxPermSize=128M JVM最大允许分配的非堆内存,按需分配

我们首先了解一下JVM内存管理的机制,然后再解释每个参数代表的含义。
1)堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。
可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,
所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
堆内存分配
JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的堆内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;
空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx 相等以避免在每次GC 后调整堆的大小。
说明:如果-Xmx 不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM,不是Throwable的,无法用try…catch捕捉。
非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。(还有一说:MaxPermSize缺省值和-server -client选项相关,
-server选项下默认MaxPermSize为64m,-client选项下默认MaxPermSize为32m。这个我没有实验。)
上面错误信息中的PermGen space的全称是Permanent Generation space,是指内存的永久保存区域。还没有弄明白PermGen space是属于非堆内存,还是就是非堆内存,但至少是属于了。
XX:MaxPermSize设置过小会导致java.lang.OutOfMemoryError: PermGen space 就是内存益出。
说说为什么会内存益出:
(1)这一部分内存用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和存放Instance的Heap区域不同。
(2)GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS 的话,就很可能出现PermGen space错误。
这种错误常见在web服务器对JSP进行pre compile的时候。
2)JVM内存限制(最大值)
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,
这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。

2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动?
通过上面对JVM内存管理的介绍我们已经了解到JVM内存包含两种:堆内存和非堆内存,另外JVM最大内存首先取决于实际的物理内存和操作系统。所以说设置VM参数导致程序无法启动主要有以下几种原因:
1) 参数中-Xms的值大于-Xmx,或者-XX:PermSize的值大于-XX:MaxPermSize;
2) -Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制,比如当前操作系统最大内存限制,或者实际的物理内存等等。说到实际物理内存这里需要说明一点的是,
如果你的内存是1024MB,但实际系统中用到的并不可能是1024MB,因为有一部分被硬件占用了。

3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置?
那为什么同样的参数在快捷方式或者命令行中有效而在eclipse.ini文件中是无效的呢?这是因为我们没有遵守eclipse.ini文件的设置规则:
参数形如“项 值”这种形式,中间有空格的需要换行书写,如果值中有空格的需要用双引号包括起来。比如我们使用-vm C:/Java/jre1.6.0/bin/javaw.exe参数设置虚拟机,
在eclipse.ini文件中要写成这样:
-vm
C:/Java/jre1.6.0/bin/javaw.exe
-vmargs
-Xms128M
-Xmx512M
-XX:PermSize=64M
-XX:MaxPermSize=128M
实际运行的结果可以通过Eclipse中“Help”-“About Eclipse SDK”窗口里面的“Configuration Details”按钮进行查看。
另外需要说明的是,Eclipse压缩包中自带的eclipse.ini文件内容是这样的:
-showsplash
org.eclipse.platform
–launcher.XXMaxPermSize
256m
-vmargs
-Xms40m
-Xmx256m
其中–launcher.XXMaxPermSize(注意最前面是两个连接线)跟-XX:MaxPermSize参数的含义基本是一样的,我觉得唯一的区别就是前者是eclipse.exe启动的时候设置的参数,
而后者是eclipse所使用的JVM中的参数。其实二者设置一个就可以了,所以这里可以把–launcher.XXMaxPermSize和下一行使用#注释掉。

4. 其他的启动参数。 如果你有一个双核的CPU,也许可以尝试这个参数:
-XX:+UseParallelGC
让GC可以更快的执行。(只是JDK 5里对GC新增加的参数)

补充:
如果你的WEB APP下都用了大量的第三方jar,其大小超过了服务器jvm默认的大小,那么就会产生内存益出问题了。
解决方法: 设置MaxPermSize大小
可以在myelipse里选中相应的服务器比如tomcat5,展开里面的JDK子项页面,来增加服务器启动的JVM参数设置:
-Xms128m
-Xmx256m
-XX:PermSize=128M
-XX:MaxNewSize=256m
-XX:MaxPermSize=256m
或者手动设置MaxPermSize大小,比如tomcat,
修改TOMCAT_HOME/bin/catalina.bat,在echo “Using CATALINA_BASE: $CATALINA_BASE”上面加入以下行:
JAVA_OPTS=”-server -XX:PermSize=64M -XX:MaxPermSize=128m

建议:将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以减少jar 文档重复占用内存

 

http://www.cnblogs.com/mingforyou/archive/2012/03/03/2378143.html

linux rsync同步设置详细指南

20 条评论

2016 年 10 月 17 日 at 下午 8:44分类:Linux

配置rsync 同步数据     rpm包安装rsync及配置

[root@Hammer home]# rpm -qa |grep rsync                 #检查系统是否安装了rsync软件包
rsync-2.6.8-3.1
[root@Hammer CentOS]# rpm -ivh rsync-2.6.8-3.1.i386.rpm # 如果没有安装则手动安装

[root@test rsync-3.0.4]# vim /etc/xinetd.d/rsync

1 配置rsync servervi /etc/xinetd.d/rsync
将disable=yes改为no

service rsync
{
disable = no
socket_type     = stream
wait            = no
user            = root
server          = /usr/bin/rsync
server_args     = –daemon
log_on_failure  += USERID
}

2 配置rsync自动启动
[root@test etc]# chkconfig rsync on
[root@test etc]# chkconfig rsync –list
rsync           on

3 配置rsyncd.conf
[root@test etc]# vim rsyncd.conf

uid = root
gid = root
use chroot = no
max connections = 4
strict modes = yes
port = 873
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log

[backup]
path = /srv
comment = This is test
auth users = scihoo
uid = root
gid = root
secrets file = /home/rsync.ps
read only = no
list = no

4 确保etc/services中rsync端口号正确
[root@test etc]# vim /etc/services
rsync           873/tcp                         # rsync
rsync           873/udp                         # rsync

5 配置rsync密码(在上边的配置文件中已经写好路径)/home/rsync.ps(名字随便写,只要和上边配置文件里的一致即可),格式(一行一个用户)
[root@test etc]# vi /home/rsync.ps
scihoo:scihoo

6 配置rsync密码文件权限
[root@test home]# chown root.root rsync.ps
[root@test home]# chmod 400 rsync.ps

7 启动配置
[root@test home]# /etc/init.d/xinetd restart
Stopping xinetd:                                           [  OK  ]
Starting xinetd:                                           [  OK  ]

8 如果xinetd没有的话,需要安装一下
[root@test home]# yum -y install xinetd

启动rsync server
RSYNC服务端启动的两种方法
9、启动rsync服务端(独立启动)
[root@test home]# /usr/bin/rsync –daemon

10、启动rsync服务端 (有xinetd超级进程启动)
[root@test home]# /etc/init.d/xinetd reload

11  加入rc.local
在各种操作系统中,rc文件存放位置不尽相同,可以修改使系统启动时把rsync –daemon加载进去。
[root@test home]# vi /etc/rc.local
/usr/local/rsync –daemon           #加入一行

12 检查rsync是否启动
[root@test home]# lsof -i :873
COMMAND  PID USER   FD   TYPE DEVICE SIZE NODE NAME
xinetd  4396 root    5u  IPv4 633387       TCP *:rsync (LISTEN)

客户端配置
1 配置三个过程就可以了
1.1 设定密码文件
1.2 测试rsync执行指令
1.3 将rsync指令放入工作排程(crontab)
[root@aj1 home]# vi /etc/xinetd.d/rsync

# default: off
# description: The rsync server is a good addition to an ftp server, as it \
#       allows crc checksumming etc.
service rsync
{
disable = yes
socket_type     = stream
wait            = no
user            = root
server          = /usr/bin/rsync
server_args     = –daemon
log_on_failure  += USERID
}

1.1  配置密码文件  (注:为了安全,设定密码档案的属性为:600。rsync.ps的密码一定要和Rsync Server密码设定案里的密码一样)
[root@aj1 home]# vi rsync.ps
sciooo

[root@aj1 home]# chown root.root .rsync.ps   # 注意必须给权限
[root@aj1 home]# chmod 600 .rsync.ps         # 必须修改权限

1.2 从服务器上下载文件
[root@aj1 rsync-3.0.4]# rsync -avz –password-file=/home/rsync.ps scihoo@192.168.0.206::backup /home/

从本地上传到服务器上去
[root@aj1 rsync-3.0.4]# rsync -avz –password-file=/home/rsync.ps /home scihoo@192.168.0.206::backup

http://www.linuxsir.org/main/?q=node/256#5.1

http://os.51cto.com/art/201101/243374.htm

JVM的内存区域划分

12 条评论

2016 年 09 月 26 日 at 下午 8:26分类:java

学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆、栈以及静态数据区。那么在Java语言当中,内存又是如何划分的呢?

由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分。在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程:

如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。

在知道了JVM内存是什么东西之后,下面我们就来讨论一下这段空间具体是如何划分区域的,是不是也像C语言中一样也存在栈和堆呢?

一.运行时数据区包括哪几部分?

根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

如上图所示,JVM中的运行时数据区应该包括这些部分。在JVM规范中虽然规定了程序在执行期间运行时数据区应该包括这几部分,但是至于具体如何实现并没有做出规定,不同的虚拟机厂商可以有不同的实现方式。

二.运行时数据区的每部分到底存储了哪些数据?

下面我们来了解一下运行时数据区的每部分具体用来存储程序执行过程中的哪些数据。

1.程序计数器

程序计数器(Program Counter Register),也有称作为PC寄存器。想必学过汇编语言的朋友对程序计数器这个概念并不陌生,在汇编语言中,程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当CPU需要执行指令时,需要从程序计数器中得到当前需要执行的指令所在存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加1或者根据转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令。

虽然JVM中的程序计数器并不像汇编语言中的程序计数器一样是物理概念上的CPU寄存器,但是JVM中的程序计数器的功能跟汇编语言中的程序计数器的功能在逻辑上是等同的,也就是说是用来指示 执行哪条指令的。

由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。

在JVM规范中规定,如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;如果线程执行的是native方法,则程序计数器中的值是undefined。

由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。

2.Java栈

Java栈也称作虚拟机栈(Java Vitual Machine Stack),也就是我们常常所说的栈,跟C语言的数据段中的栈类似。事实上,Java栈是Java方法执行的内存模型。为什么这么说呢?下面就来解释一下其中的原因。

Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。讲到这里,大家就应该会明白为什么 在 使用 递归方法的时候容易导致栈内存溢出的现象了以及为什么栈区的空间不用程序员去管理了(当然在Java中,程序员基本不用关系到内存分配和释放的事情,因为Java有自己的垃圾回收机制),这部分空间的分配和释放都是由系统自动实施的。对于所有的程序设计语言来说,栈这部分空间对程序员来说是不透明的。下图表示了一个Java栈的模型:

局部变量表,顾名思义,想必不用解释大家应该明白它的作用了吧。就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。

操作数栈,想必学过数据结构中的栈的朋友想必对表达式求值问题不会陌生,栈最典型的一个应用就是用来对表达式求值。想想一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。

指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。

方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰。

3.本地方法栈

本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,并没有对本地方发展的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。

4.堆

在C语言中,堆这部分空间是唯一一个程序员可以管理的内存区域。程序员可以通过malloc函数和free函数在堆上申请和释放空间。那么在Java中是怎么样的呢?

Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。只不过和C语言中的不同,在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。因此这部分空间也是Java垃圾收集器管理的主要区域。另外,堆是被所有线程共享的,在JVM中只有一个堆。

5.方法区

方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。

在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。

在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

在JVM规范中,没有强制要求方法区必须实现垃圾回收。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。

以上为个人看法和观点,如有不正之处希望谅解并欢迎指正。

  参考资料:

http://blog.csdn.net/ns_code/article/details/17565503

http://www.cnblogs.com/sunada2005/p/3577799.html

《深入理解Java虚拟机》

《Java虚拟机规范 SE7》

线程池

13 条评论

2016 年 08 月 23 日 at 下午 9:11分类:java

线程池的优点:

  • 重用线程池中的线程,避免频繁创建和销毁带来的性能开销
  • 可以有效控制线程池中的最大并发数,避免大量线程之间互相抢占系统资源导致阻塞
  • 可以对线程进行简单管理。

线程运行机制

  • 开启线程过多,会消耗cpu资源
  • 单核cpu,同一时刻只能处理一个线程,多核cpu同一时刻可以处理多个线程
  • 操作系统为每个运行线程安排一定的CPU时间—-时间片,系统通过一种循环的方式为线程提供时间片,线程在自己的时间内运行,因为时间相当短,多个线程频繁地发生切换,因此给用户的感觉就是好像多个线程同时运行一样,但是如果计算机有多个CPU,线程就能真正意义上的同时运行了.

线程池的作用

  • 线程池是预先创建线程的一种技术。线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中,然后对这些资源进行复用。减少频繁的创建和销毁对象。
  • 频繁创建和销毁线程耗资源,耗时间
  • 因为有的线程执行时间比创建和销毁一个线程的时间还短

解读EXPLAIN执行计划中的key_len

16 条评论

2016 年 02 月 08 日 at 下午 8:46分类:Mysql

EXPLAIN中的key_len一列表示什么意思,该如何解读?

EXPLAIN执行计划中有一列 key_len 用于表示本次查询中,所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了。

在这里 key_len 大小的计算规则是:

  • 一般地,key_len 等于索引列类型字节长度,例如int类型为4-bytes,bigint为8-bytes;
  • 如果是字符串类型,还需要同时考虑字符集因素,例如:CHAR(30) UTF8则key_len至少是90-bytes;
  • 若该列类型定义时允许NULL,其key_len还需要再加 1-bytes;
  • 若该列类型为变长类型,例如 VARCHAR(TEXT\BLOB不允许整列创建索引,如果创建部分索引,也被视为动态列类型),其key_len还需要再加 2-bytes;

综上,看下面几个例子:

列类型 key_len 备注
id int key_len = 4+1 = 5 允许NULL,加1-byte
id int not null key_len = 4 不允许NULL
user char(30) utf8 key_len = 30*3+1 允许NULL
user varchar(30) not null utf8 key_len = 30*3+2 动态列类型,加2-bytes
user varchar(30) utf8 key_len = 30*3+2+1 动态列类型,加2-bytes;允许NULL,再加1-byte
detail text(10) utf8 key_len = 30*3+2+1 TEXT列截取部分,被视为动态列类型,加2-bytes;且允许NULL

备注,key_len 只指示了WHERE中用于条件过滤时被选中的索引列,是不包含 ORDER BY/GROUP BY 这部分被选中的索引列。

例如,有个联合索引 idx1(c1, c2, c3),3个列均是INT NOT NULL,那么下面的这个SQL执行计划中,key_len的值是8而不是12:

SELECT…WHERE c1=? AND c2=? ORDER BY c1;

Java中的堆和栈的区别

12 条评论

2016 年 02 月 08 日 at 下午 8:05分类:java

当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先出(Last In First Out)的顺序的数据结构,这就是java.util.Stack。这种情况下,不免让很多人更加费解前面的问题。事实上,堆和栈都是内存中的一部分,有着不同的作用,而且一个程序需要在这片区域上分配内存。众所周知,所有的Java程序都运行在JVM虚拟机内部,我们这里介绍的自然是JVM(虚拟)内存中的堆和栈。

区别

java中堆和栈的区别自然是面试中的常见问题,下面几点就是其具体的区别

各司其职

最主要的区别就是栈内存用来存储局部变量和方法调用。
而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

独有还是共享

栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

异常错误

如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。

空间大小

栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。
你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。

这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。

如何查看linux版本 如何查看LINUX是多少位

22 条评论

2015 年 11 月 30 日 at 下午 8:07分类:Linux

一、如何得知自己正在使用的linux是什么版本呢,下面的几种方法将给你带来答案!

1. 查看内核版本命令:

1) [root@q1test01 ~]# cat /proc/version

Linux version 2.6.9-22.ELsmp (bhcompile@crowe.devel.redhat.com) (gcc version 3.4.4 20050721 (Red Hat 3.4.4-2)) #1 SMP Mon Sep 19 18:00:54 EDT 2005

2) [root@q1test01 ~]# uname -a

Linux q1test01 2.6.9-22.ELsmp #1 SMP Mon Sep 19 18:00:54 EDT 2005 x86_64 x86_64 x86_64 GNU/Linux

3) [root@q1test01 ~]# uname -r

2.6.9-22.ELsmp

2. 查看linux版本:

1) 登录到服务器执行 lsb_release -a ,即可列出所有版本信息,例如:

[root@3.5.5Biz-46 ~]# [root@q1test01 ~]# lsb_release -a

LSB Version: :core-3.0-amd64:core-3.0-ia32:core-3.0-noarch:graphics-3.0-amd64:graphics-3.0-

ia32:graphics-3.0-noarch

Distributor ID: RedHatEnterpriseAS

Description: Red Hat Enterprise Linux AS release 4 (Nahant Update 2)

Release: 4

Codename: NahantUpdate2

注:这个命令适用于所有的linux,包括Redhat、SuSE、Debian等发行版。

2) 登录到linux执行cat /etc/issue,例如如下:

[root@q1test01 ~]# cat /etc/issue

Red Hat Enterprise Linux AS release 4 (Nahant Update 2)

Kernel \r on an \m

3) 登录到linux执行cat /etc/redhat-release ,例如如下:

[root@q1test01 ~]# cat /etc/redhat-release

Red Hat Enterprise Linux AS release 4 (Nahant Update 2)

注:这种方式下可以直接看到具体的版本号,比如 AS4 Update 1

4)登录到linux执行rpm -q redhat-release ,例如如下:

[root@q1test01 ~]# rpm -q redhat-release

redhat-release-4AS-3

注:这种方式下可看到一个所谓的release号,比如上边的例子是3

这个release号和实际的版本之间存在一定的对应关系,如下:

redhat-release-3AS-1 -> Redhat Enterprise Linux AS 3

redhat-release-3AS-7.4 -> Redhat Enterprise Linux AS 3 Update 4

redhat-release-4AS-2 -> Redhat Enterprise Linux AS 4

redhat-release-4AS-2.4 -> Redhat Enterprise Linux AS 4 Update 1

redhat-release-4AS-3 -> Redhat Enterprise Linux AS 4 Update 2

redhat-release-4AS-4.1 -> Redhat Enterprise Linux AS 4 Update 3

redhat-release-4AS-5.5 -> Redhat Enterprise Linux AS 4 Update 4

另:第3)、4)两种方法只对Redhat Linux有效。

二、如何查看LINUX是多少位

1. 查看linux机器是32位还是64位的方法:

file /sbin/init 或者file /bin/ls
/sbin/init: ELF64-bitLSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

如果显示 64-bit 则为64位;

file /sbin/init
/sbin/init: ELF32-bitLSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped

如果显示为32 bit 则为32bit;

uname -a:
uname -a
Linux pmx002**.**.** 2.6.32-71.el6.x86_64 #1 SMP Wed Sep 1 01:33:01 EDT 2010x86_64x86_64 x86_64 GNU/Linux

x86_64表示64位机器

uname -a
Linux pmx0**.**.** 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39 EST 2005i686i686 i386 GNU/Linux

i686表示32位机器

i686 只是i386的一个子集,支持的cpu从Pentium 2 (686)开始,之前的型号不支持.

备注:

1. i386 适用于intel和AMD所有32位的cpu.以及via采用X86架构的32的cpu.

intel平台包括8086,80286,80386,80486,奔腾系列(1.2.3.4)、赛扬系列,Pentium D系列

以及centrino P-M,core duo 等.

2. X86_64 适用于intel的Core 2 Duo, Centrino Core 2 Duo, and Xeon 和AMD Athlon64/x2, Sempron64/x2, Duron64等采用X86架构的64位cpu.

3. PPC 适用于Apple Macintosh G3, G4, G5, PowerBook, and other non-Intel models

安装DVD包括的软件要比安装光盘多一些,安装DVD也包括了两种图形界面(KDE和gnome).

4.Jigdo

也可以通过 Jigdo 下载 Fedora 发行版。Jigdo 可以加速下载安装盘的 ISO 镜像。同 BT 下载等待任务完全完成所不同,Jidgo 自动定位最快的镜像服务器(通过 Fedora 镜像管理器),并且从中下载所需要的文件。为了减少所需的网络流量,可以让 Jigdo 扫描现存的 DVD 或 CD 介质。这个功能对于以下用户特别有用。

2. getconf LONG_BIT
在32位和64位机器上运行如下命令,结果如下:
[b@002 ~]$ getconf LONG_BIT
64

[root@pmx4 /]# getconf LONG_BIT
32

遍历Map的四种方法

3 条评论

2015 年 11 月 06 日 at 下午 6:05分类:java

public static void main(String[] args) {

  Map<String, String> map = new HashMap<String, String>();
  map.put("1", "value1");
  map.put("2", "value2");
  map.put("3", "value3");

  //第一种:普遍使用,二次取值
  System.out.println("通过Map.keySet遍历key和value:");
  for (String key : map.keySet()) {
   System.out.println("key= "+ key + " and value= " + map.get(key));
  }

  //第二种
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
  while (it.hasNext()) {
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第三种:推荐,尤其是容量大时
  System.out.println("通过Map.entrySet遍历key和value");
  for (Map.Entry<String, String> entry : map.entrySet()) {
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第四种
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
  for (String v : map.values()) {
   System.out.println("value= " + v);
  }
 }