Hadoop集群退不出安全模式(safe model)的解决方案

由于磁盘满了,hadoop集群进入了安全模式,在网上中了很多方案,方案中的思路都测试过,基本没有行的通。

以下是方案中的解决办法:

这个是由于HDFS被异常关闭之后造成数据库的不一致状态而造成的:

Lattest collection of black diamond rings, black diamond engagement rings, black engagement rings. The unique black storm is coming. This kind of unique gold ring will give you a new look. All free shipping Over $99 at very lowest price.

1)等

当然,这个是最安全的方式,如果等了太长时间仍处于这个状态,尝试下面的方法

2)强制退出安全模式,

hadoop dfsadmin -safemode leave  怎么退都退不出,通过leave退出了,但是通过get命令,还是处于集群模式。

尝试用”hadoop fsck /” 工具修复

通过hadoop fsck工具检查和delete也不行,操作记录如下:http://www.tuicool.com/articles/FnMFNjN

3)删除tmp文件目录下的所有的文件,重新format

这种方式非常暴力,所有的数据均没有了

 

 

本次解决方案:

1、在linux系统中,拼命删除一些log日志,腾出了几百兆空间。

2、使用命令  hadoop dfsadmin -safemode leave  成功退出

3、删除Job运行时的临时文件, hadoop fs –rm –r /tmp 目录

4、集群又活过来了

Phoenix兼容性及部署安装

技术调研-版本兼容性-软件准备

1、业务系统中需要使用Phoenix 

http://phoenix.apache.org

2、Phoenix  的发行版本支持0.98,1.0.1.1

wps5CFB.tmp

3、定位hbase的版本

hbase官方文档中,hbase 1.1.x 替代了0.98,1.0 两个版本。所以,我们的hbase就选择1.1的版本了。

wps5CFC.tmp

4、Hbase 1.1.x的兼容性表中可以定位到 hadoop2.5.x

http://hbase.apache.org/book.html#configuration

wps5D0D.tmp

5、下载 hadoop2.5.x的源码

http://hadoop.apache.org/releases.html

wps5D0E.tmp

6、编译hadoop源码

wget http://mirrors.cnnic.cn/apache/hadoop/common/hadoop-2.5.2/hadoop-2.5.2-src.tar.gz

tar -zxvf hadoop-2.5.2-src.tar.gz

cd hadoop-2.5.2-src

mvn package -Pdist,native -DskipTests -Dtar

注意:编译的时候必须使用jdk 1.7,否则关于doc的问题会有很多

编译完成之后 /hadoop-2.5.2-src/hadoop-dist/target

7、安装hadoop

8、安装hbase

9、安装Phoenix

1、下载安装包

http://apache.fayea.com/phoenix/

2、将安装包中的所有jar包拷贝到hbase的lib目录下,然后重启hbase

3、启动sqlline.py

4、语法参考

http://forcedotcom.github.io/phoenix/index.html

Redis常用命令,开发使用宝典

Necklaces and Pendants by DAZZBOX shine in very good price which is a once in a lifetime piece. Free shipping for over $99. Just come here and get you favorite one.
Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用。在编程时,比如使用Redis 的Java语言包,这些命令都有对应的方法。下面将Redis提供的命令做一总结。

官网命令列表:http://redis.io/commands (英文)

1、连接操作相关的命令
  • quit:关闭连接(connection)
  • auth:简单密码认证
2、对value操作的命令
  • exists(key):确认一个key是否存在
  • del(key):删除一个key
  • type(key):返回值的类型
  • keys(pattern):返回满足给定pattern的所有key
  • randomkey:随机返回key空间的一个key
  • rename(oldname, newname):将key由oldname重命名为newname,若newname存在则删除newname表示的key
  • dbsize:返回当前数据库中key的数目
  • expire:设定一个key的活动时间(s)
  • ttl:获得一个key的活动时间
  • select(index):按索引查询
  • move(key, dbindex):将当前数据库中的key转移到有dbindex索引的数据库
  • flushdb:删除当前选择数据库中的所有key
  • flushall:删除所有数据库中的所有key
3、对String操作的命令
  • set(key, value):给数据库中名称为key的string赋予值value
  • get(key):返回数据库中名称为key的string的value
  • getset(key, value):给名称为key的string赋予上一次的value
  • mget(key1, key2,…, key N):返回库中多个string(它们的名称为key1,key2…)的value
  • setnx(key, value):如果不存在名称为key的string,则向库中添加string,名称为key,值为value
  • setex(key, time, value):向库中添加string(名称为key,值为value)同时,设定过期时间time
  • mset(key1, value1, key2, value2,…key N, value N):同时给多个string赋值,名称为key i的string赋值value i
  • msetnx(key1, value1, key2, value2,…key N, value N):如果所有名称为key i的string都不存在,则向库中添加string,名称key i赋值为value i
  • incr(key):名称为key的string增1操作
  • incrby(key, integer):名称为key的string增加integer
  • decr(key):名称为key的string减1操作
  • decrby(key, integer):名称为key的string减少integer
  • append(key, value):名称为key的string的值附加value
  • substr(key, start, end):返回名称为key的string的value的子串
4、对List操作的命令
  • rpush(key, value):在名称为key的list尾添加一个值为value的元素
  • lpush(key, value):在名称为key的list头添加一个值为value的 元素
  • llen(key):返回名称为key的list的长度
  • lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)
  • ltrim(key, start, end):截取名称为key的list,保留start至end之间的元素
  • lindex(key, index):返回名称为key的list中index位置的元素
  • lset(key, index, value):给名称为key的list中index位置的元素赋值为value
  • lrem(key, count, value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0从头至尾删除count个值为value的元素,count<0从尾到头删除|count|个值为value的元素。 lpop(key):返回并删除名称为key的list中的首元素 rpop(key):返回并删除名称为key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。即当timeout为0时,若遇到名称为key i的list不存在或该list为空,则命令结束。如果timeout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对keyi+1开始的list执行pop操作。
  • brpop(key1, key2,… key N, timeout):rpop的block版本。参考上一命令。
  • rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部
5、对Set操作的命令
  • sadd(key, member):向名称为key的set中添加元素member
  • srem(key, member) :删除名称为key的set中的元素member
  • spop(key) :随机返回并删除名称为key的set中一个元素
  • smove(srckey, dstkey, member) :将member元素从名称为srckey的集合移到名称为dstkey的集合
  • scard(key) :返回名称为key的set的基数
  • sismember(key, member) :测试member是否是名称为key的set的元素
  • sinter(key1, key2,…key N) :求交集
  • sinterstore(dstkey, key1, key2,…key N) :求交集并将交集保存到dstkey的集合
  • sunion(key1, key2,…key N) :求并集
  • sunionstore(dstkey, key1, key2,…key N) :求并集并将并集保存到dstkey的集合
  • sdiff(key1, key2,…key N) :求差集
  • sdiffstore(dstkey, key1, key2,…key N) :求差集并将差集保存到dstkey的集合
  • smembers(key) :返回名称为key的set的所有元素
  • srandmember(key) :随机返回名称为key的set的一个元素
6、对zset(sorted set)操作的命令
  • zadd(key, score, member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序。
  • zrem(key, member) :删除名称为key的zset中的元素member
  • zincrby(key, increment, member) :如果在名称为key的zset中已经存在元素member,则该元素的score增加increment;否则向集合中添加该元素,其score的值为increment
  • zrank(key, member) :返回名称为key的zset(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
  • zrevrank(key, member) :返回名称为key的zset(元素已按score从大到小排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
  • zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素
  • zrevrange(key, start, end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素
  • zrangebyscore(key, min, max):返回名称为key的zset中score >= min且score <= max的所有元素 zcard(key):返回名称为key的zset的基数 zscore(key, element):返回名称为key的zset中元素element的score zremrangebyrank(key, min, max):删除名称为key的zset中rank >= min且rank <= max的所有元素 zremrangebyscore(key, min, max) :删除名称为key的zset中score >= min且score <= max的所有元素
  • zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):对N个zset求并集和交集,并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score,在进行AGGREGATE运算前,都要乘以对于的WEIGHT参数。如果没有提供WEIGHT,默认为1。默认的AGGREGATE是SUM,即结果集合中元素的score是所有集合对应元素进行SUM运算的值,而MIN和MAX是指,结果集合中元素的score是所有集合对应元素中最小值和最大值。
7、对Hash操作的命令
        • hset(key, field, value):向名称为key的hash中添加元素field<—>value
        • hget(key, field):返回名称为key的hash中field对应的value
        • hmget(key, field1, …,field N):返回名称为key的hash中field i对应的value
        • hmset(key, field1, value1,…,field N, value N):向名称为key的hash中添加元素field i<—>value i
        • hincrby(key, field, integer):将名称为key的hash中field的value增加integer
        • hexists(key, field):名称为key的hash中是否存在键为field的域
        • hdel(key, field):删除名称为key的hash中键为field的域
        • hlen(key):返回名称为key的hash中元素个数
        • hkeys(key):返回名称为key的hash中所有键
        • hvals(key):返回名称为key的hash中所有键对应的value
        • hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
8、持久化
  • save:将数据同步保存到磁盘
  • bgsave:将数据异步保存到磁盘
  • lastsave:返回上次成功将数据保存到磁盘的Unix时戳
  • shundown:将数据同步保存到磁盘,然后关闭服务
9、远程服务控制
  • info:提供服务器的信息和统计
  • monitor:实时转储收到的请求
  • slaveof:改变复制策略设置
  • config:在运行时配置Redis服务器

win7+myEclipse远程调试部署在linux+tomcat的项目

联想服务器导航系统的组件有很多个,其中一个组件是运行在tomcat下的webApp。
The fine pendant gives your style year-round warmth with its radiant design and Cubic Zirconia.  Starfish design. Border features a pavé-set, round Cubic Zirconia accent and beaded texture. Free DHL shipping over $99.
webApp需要使用JDK提供的API与底层的linux(redhat)系统进行交互,该API命令如下:Runtime.getRuntime().exec()。

所以这个WebApp运行的环境必须是在linux下的,而本人的开发环境却是Win7+myEclipse10+tomcat,直接导致程序运行不起来。

要调试整个程序只能远程调试运行在linux+tomcat的项目。而在MyEclipse的debug里有remote java application 这个工具,可以使用它来设置远程调试。

第1步:   修改catalina.sh 文件

修改Tomcat安装目录下的/usr/apache-tomcat-6.0.26/bin /catalina.sh 文件;在这个文件中加入如下内容:(我是加在文件的第一行)

CATALINA_OPTS= –Xdebug –Xrunjdwp:transport=dt_socket,address=10000,server=y,suspend=n

(这里address=10000,表示要远程调试连接的端口号),修改后保存此文件。

第2步:   关掉防火墙

liunx下用如下命令关闭防火墙:

/etc/rc.d/init.d/iptables stop

第3步:   部署项目程序:

将Windows 系统下的 E:\Tomcat 6.0\webapps 目录下要调试的项目程序,部署到Linux系统 /usr/apache-tomcat-6.0.26/webapps 目录下。(必须保证Linux下的程序与MyEclipse中的程序一致)

第4步:   重新启动Tomcat服务

停止Tomcat服务,使用如下命令:

# /usr/apache-tomcat-6.0.26/bin/shutdown.sh

启动Tomcat服务,使用如下命令:

# /usr/apache-tomcat-6.0.26/bin/startup.sh

第5步:   新建remote java application

然后打开MyEclipse,新建一个remote java application ,在打开的MyEclipse里的工具栏里有个小虫子debug的图标,点击旁边的下三角符号,选择open debug dialog,打开debug配置对话框,在最后一项有个remote java application ,选中后右击new一个出来。

第6步:   配置remote java application

在name里填个名字,然后在下面的connect的project里选中MyEclipse里的项目(即部署在Linux系统下的项目,注意要和远程的项目对应)。connection type就用默认的,connection properties的Host里填上远程机器的ip地址(即Linux系统的IP地址), 第二项Port里填端口:10000,(Port端口和catalina.sh 文件中的address值一样,同时要保证这个端口没被其他服务使用)。配置完成后直接点击“Debug”按钮,开启调试线程,在MyEclipse的debug窗口中会看到有一个调试的线程启动,说明配置成功。

第7步:   设置断点:

在MyEclipse中打开要调试的文件,在需要的地方打上断点,访问远程机器的程序,当程序运行到断点处时会停住,即可进行远程调试。

(注:在调试过程中可以对本地程序进行修改,以达到想要的效果。但所修改的文件并不会影响到远程机器上文件,所以修改过的文件必须更新到远程机器上。)

Java专题(1)-Java概述、Java发展、Java虚拟机

前言

由于博客没有备份,在一次莫名其妙的的事故中,丢失了之前所有的文章。根据本地文档和搜索引擎快照恢复了一些,但还有大部分文章永久性的丢失了。丢失文章的感觉就仿佛记忆被人抹去一块,明明知道她在哪里,搜遍脑海却是空白一片,心中不爽的很,所以打算从头再来,并借此机会系统的整理所学的知识。

JAVA是什么

作为一个程序员,说到java立马会想到Java是一门编程语言。 其实Java不仅仅是一门编程语言,还是一个由一系列计算机软件和规范形成的技术体系,这个体系提供了完整的用语软件开发和跨平台部署的支持环境,并广泛用语嵌入式系统,移动终端,企业服务器,大型机等各种场合。

sun(oracle)官方定义的Java技术体系包括以下组成部分:

1:Java程序设计语言

2:各种硬件平台上的Java虚拟机

3:Class文件格式

4:Java API类库

5:来自商业机构和开源社区的第三方Java类库 那作为程序猿经常说的JDK,完整的英文名称是 Java Development Kit ,翻译过来就是Java 开发工具包,它包括了Java程序设计语言、Java虚拟机、Java API这三个部分。而JRE包括Java API 类库的一部分和Java虚拟机两个部分,JRE是支持Java程序运行的标准环境。

Java的发展

Java语言的前身是Oak(橡树),橡树是运用在各种消费型电子产品(如机顶盒、冰箱、收音机、导航)上的程序语言。但是Oak在当时的消费品市场上不太成功,因为时代决定了那时候的消费产品的市场及功能形态,就如盛大05年做的盛大盒子一样,做的太早就没有做起来。现在的做机顶盒、网络盒子的发展趋势就特别好,比如小米盒子,乐视TV。所以Oak产品就是顺应当时的市场趋势蜕变成了Java语言,之后就一路狂奔。

接下来我们看看Java的几个大版本和相应的功能。

1:1995年5月23日,Java 1.0 在sunworl的大会上,提出write once,run anywhere的口号。

2:1996年1月23日,JDK 1.0发布。JDK 1.0版本代表技术包括:Java虚拟机、Applet、AWT等。Applet是一种可以运行在HTML网页上的小程序,刚开始出来的时候红极一时。

3:1997年2月19日,JDK 1.1发布。JDK1.1版本代表的技术包括:JAR文件格式、JDBC、JavaBeans、RMI(Remote Method Invocation 远程方法调用 )等,内部类和反射技术在这个时候出现了。

4:1998年12月4日,JDK1.2发布。JDK1.2是一个里程碑式的版本。这个版本中Java技术体系中被分为三个方向,分别是J2SE、J2EE、J2ME。其中J2SE面向桌面应用开发、J2EE面向企业级开发、J2ME面向手机和移动终端开发。这个版本还涌现了很多代表性的技术:EJB、Java Plug-in、Java IDL、Swing等,并且有三个虚拟机可以被选择,分别是Classic VM、HotSpot和Exact VM,其中HotSpot和Exact VM都带有即时编译(JIT)的功能,所以也赋予了JDK1.2即时编译的特点。程序猿编程必杀技集合类也在出现在这个版本中。

5:2000年5月8日,JDK1.3发布。JDK1.3应该说没有特别的更新。PS下野史,我之前看过一篇报道Java老板的文章,是在《浪潮之巅》还是什么地方,说是因为JDK1.2出来之后,市场反应并不是激烈,公司一度要关门和破产,一年后这个老板不甘心,基于1.2重新发布了一个版本,并广而告之,说了JDK 1.3的很多特性。然后吸引了很多热爱技术和单纯的程序猿的关注。

6:2002年2月13日,JDK1.4发布。JDK1.4是Java真正走向成熟的一个版本,有很多牛逼公司参与(IBM)。发布了很多新特性,包括正则表达式、异常链、NIO、日志类、XML解析器等等。

7:2004年9月30日,JDK1.5发布。JDK1.5包含了我们现在大多数应用场景需要的技术,如自动装箱、泛型、自动注解、枚举、可变长参数、遍历循环(foreach)等,这个版本还改进了JMM(Java内存模型)、提供了并发包java.util.concurrent等等。略微熟悉并发技术的童鞋,2004年并发包就发布了,我们有什么理由不搞定她。

8:2006年12月11日,JDK1.6发布,这个版本对JVM内部做了大量的优化,包括锁与同步、垃圾收集、类加载机制等。同时也将JDK1.3定义的三分方向的名字进行了修改,变成了Java SE、Java EE、Java ME。虽然改了名字,但很多老程序猿依然喜欢用J2EE等名称,所以如果你想装老牛,可以使用J2EE,逼格一下子提升不少!

9:2009年2月19日,JDK1.7发布第一个版本。由于JDK1.6之后,因为代码的复杂性增加、经济危机、公司经营不善等各种原因,计划中的JDK1.7难产了,所以一直以JDK1.6 update x进行发布。JDK1.7原本规划了10个里程碑,本次发布只完成了第一个里程碑,之后就是长期跳票。

10:2013年9月9日,JDK1.8通用版发布,原本属于JDK1.7规划中的特性lambda表达式在该版本中出现。lambda表达式我没有用过,据说性能提升一大截。

11:关于JDK1.9,Oracle公司期望JVM能够管理数以GB的Java堆,能够更高效地与本地代码集成,并且令Java虚拟机运行时及可能减少人工干预,能够自动调节。

Java的虚拟机

现在面试几年的Java老程序猿,你不问问java虚拟机的相关知识,反问会显得面试者不够专业,大多数程序猿理解java虚拟机基本上都是HotSpot,其实Java虚拟机有很多很多种。

1:JDK1.2中出现了三个java虚拟机,Classic VM、HotSpot和Exact VM。其中HotSpot和Exact VM都带有即时编译(JIT)的功能,而Classic VM只能使用外挂的形式使用即时编译功能,虽然没有先进的功能,但是Classic VM是Java历史上第一款Java虚拟机,并在JDK1.2及之前都是默认的虚拟机。Classic VM基于handler方式进行GC。

2:Exact VM是一个短暂的Java虚拟机,她能知道一个reference类型到底是一个内存地址还是实实在在的值。基于此提供了准确式的GC回收机制。

3:JDK1.3之后HotSpot成为了默认的虚拟机,她集成了Exact VM准确式内存管理的优点,并有更好的热点探测技术(Exact VM中也有)。HotSpot VM的热点代码探测即时能力可以通过执行计数器找出最具有编译价值的代码,然后通过JIT编辑器以方法为单位进行编译。2007年左右HotSpot随java开源,同时成为了开源openJDK的虚拟机。

4:除此之外,还有很多java虚拟机,如优秀的商用JVM虚拟机还有IBM J9 VM,BEA Jrockit ,其中BEA Jrockit 已经被oracle收购。优秀的定制平台的JVM虚拟机还有AZUL VM 、BEA Liquid VM 。开源的虚拟机有Apache Harmony、Google Android Dalvik VM。研究用的Sun Mobile-Embedded VM 、Meta-Circular VM。以及微软的Microsoft JVM。

Java专题(2)-Java内存模型

前言

由于博客没有备份,在一次莫名其妙的的事故中,丢失了之前所有的文章。根据本地文档和搜索引擎快照恢复了一些,但还有大部分文章永久性的丢失了。丢失文章的感觉就仿佛记忆被人抹去一块,明明知道她在哪里,搜遍脑海却是空白一片,心中不爽的很,所以打算从头再来,并借此机会系统的整理所学的知识。

Java内存模型

如果你是一个老程序猿,面试的时候,肯定会被问到JMM(Java 内存模型)。对面试官的问题(可能并不深奥)回答的深度,直接决定了面试官对你的评价。大多数情况下,面试官其实并不了解的比你多,因为不是每个面试官都有机会实践或深入实践Java虚拟机。不管怎么样,我们先来了解下JMM的一些概念。 Java虚拟机在执行Java程序的过程中,会把它所管理的内存划分为若干个不同的数据区。这些区域有个字的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户线程的启动和结束而建立和销毁,我们可以将这些区域统称为Java运行时数据区域。 为了学习和描述方便,我从网上搜得一张内存模型的图片,并简单的修改了下。 jmm 如上图所示,Java虚拟机运行时数据区域被分为五个区域:堆(Heap)、栈(Stack)、本地方法栈(Native Stack)、方法区(Method Area)、程序计数器(Program Count Register)

依次说说他们都存储了些什么数据。

堆(Heap)

对于大多数应用来说,Java Heap是Java虚拟机锁管理的内存的最大一块,这块区域随着虚拟机的启动而创建。在实际的运用中,我们创建的对象和数组就是存放在堆里面。如果你听说线程安全的问题,就会很明确的知道Java Heap是一块共享的区域,操作共享区域的成员就有了锁和同步。 与Java Heap相关的还有Java的垃圾回收机制(GC),Java Heap是垃圾回收器管理的主要区域。程序猿所熟悉的新生代、老生代、永久代的概念就是在堆里面,现在大多数的GC基本都采用了分代收集算法。如果再细致一点,Java Heap还有Eden空间,From Survivor空间,To?Survivor空间等。 Java Heap可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。 xsd   栈(Stack

相对于Java Heap来讲,Java Stack是线程私有的,她的生命周期与线程相同。Java Stack描述的是Java方法执行时的内存模型,每个方法执行时都会创建一个栈帧(Stack Frame)用语存储局部变量表、操作数栈、动态链接、方法出口等信息。从下图从可以看到,每个线程在执行一个方法时,都意味着有一个栈帧在当前线程对应的栈帧中入栈和出栈。 stackframe 图中可以看到每一个栈帧中都有局部变量表。局部变量表存放了编译期间的各种基本数据类型,对象引用等信息。

本地方法栈(Native Stack)

本地方法栈(Native Stack)与Java虚拟机站(Java Stack)所发挥的作用非常相似,他们之间的区别在于虚拟机栈为虚拟机栈执行java方法(也就是字节码)服务,而本地方法栈则为使用到Native方法服务。

方法区(Method Area)

方法区(Method Area)与堆(Java Heap)一样,是各个线程共享的内存区域,她用语存储一杯虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是她却有一个别名叫做非堆(Non-Heap)。分析下Java虚拟机规范,之所以把方法区描述为堆的一个逻辑部分,应该觉得她们都是存储数据的角度出发的。一个存储对象数据(堆),一个存储静态信息(方法区)。 在上文中,我们看到堆中有新生代、老生代、永久代的描述,其中永久代使用了删除线,因为永久代本身不在堆中。为什么我们将新生代、老生代、永久代三个概念一起说,那是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。这样HotSpot的垃圾收集器就能想管理Java堆一样管理这部分内存。简单点说就是HotSpot虚拟机中内存模型的分代,其中新生代和老生代在队中,永久代使用方法区实现。根据官方发布的路线图信息,现在也有放弃永久代并逐步采用Native Memory来实现方法区的规划,在JDK1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出。

程序计数器(Program Count Register)

程序计数器(Program Count Register)是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等技术功能都需要依赖的计数器来完成。 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式(CPU时间片)来实现的,在任何一个确定的时刻,一个处理器(内核)都只会执行一条线程中的指令。因为,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们成这类内存区域为“线程私有”的内存。

总结

1:线程私有的数据区域有程序计数器(Program Count Register)、Java虚拟机栈(Java Stack)、本地方法栈(Native Stack),从内存分配的角度来看,线程共享的Java堆中可以划分为多个线程私有的分配缓冲区(Thrad Local Allocation Buffer,TLAB)。

2:线程共有的数据区域有堆(Java Heap)、方法区。

3:Java虚拟机会有OOM异常的区域有堆(Java Heap)、栈(Java Stack)、本地方法栈(Native Stack)、方法区(Method Area)、运行常量池(Runtime Constant Pool)。

  • 堆的空间再也不能存放新的对象时,会抛出OutOfMemoryError;
  • 栈中有栈,栈帧可以动态扩展,当栈帧扩展无法申请到足够的内存时,会抛出OutOfMemoryError;
  • 本地方法栈与Java 栈一样,栈帧可以动态扩展,当栈帧扩展无法申请到足够的内存时,会抛出OutOfMemoryError;
  • 方法区无法满足内存分配需求时,如即时编译的代码,栈帧可以动态扩展,当栈帧扩展无法申请到足够的内存时,会抛出OutOfMemoryError;
  • 运行常量池(Runtime Constant Pool)–运行常量池是方法区的一部分,主要存放常量信息,运行时产生的新常量也会放在这中,当常量在无法申请到内存时,会抛出OutOfMemoryError。

Java专题(3)-Java对象的创建及对象实例化过程

前言

由于博客没有备份,在一次莫名其妙的的事故中,丢失了之前所有的文章。根据本地文档和搜索引擎快照恢复了一些,但还有大部分文章永久性的丢失了。丢失文章的感觉就仿佛记忆被人抹去一块,明明知道她在哪里,搜遍脑海却是空白一片,心中不爽的很,所以打算从头再来,并借此机会系统的整理所学的知识。
The workmanship and styling of this original cubic zirconia link bracelet separate it from traditional bracelets seen in most fine jewelry stores. All free shipping Over $99 at very lowest price.
Java对象的创建

我们知道创建对象的有四种方式:

1)new关键字创建对象。

2)通过发射技术创建对象。

3)调用对应的clone方法,一个对象运行到每个阶段之后,实现现有的状态值创建一个新对象。

4)运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。

这篇文章主要讲使用new关键字创建一个对象的过程:

1)要创建一个对象,就需要这个对象class文件,我们知道class文件是存放在JMM的方法区,并且方法区的常量池中有定位到这个class文件的符号引用。所以当虚拟机要new一个对象的时候,首先就要检查这个类在常量池中对应的符号引用,并且检查这个符号引用的类是否已经被加载、解析和初始化过。如果没有就必须先执行类的加载过程。

2)检查通过后,Java虚拟机将会在堆中为新生的对象分配内存。而对象的所需的大小是在类加载完毕之后便可完全确定的。所以这个动作就好比是把一块确定大小的内存从java堆中划分出来。划分内存有两种方式,一种是指针碰撞,另一种是空闲列表。 指针碰撞的概念是假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的一边放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是将指针想空闲的一移动一段与对象大小相等的距离。 空闲列表,如果Java堆中的内存并不是完整的,已使用的内存和空闲的内存相互交错,那就没有办法进行简单的指针碰撞了,虚拟机就必须维护一个列表,记录那些内存可用,在分配的事实从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种方式称为“空闲列表”。 选择指针碰撞,还是空闲列表由所采用的垃圾收集器是否压缩整理的功能决定。 我们知道对象创建在虚拟机中是频繁的行为,在多线程的情况下就会需要保证对内存操作的原子性,所以就需要从线程共享的Java堆中可以划分为多个线程私有的分配缓冲区(Thrad Local Allocation Buffer,TLAB)。

3)内存分配完成后,虚拟机需要将分配的内存空间都初始化为零值。这一步操作保证对象实例的字段能在Java代码中可以不赋初始值就直接使用。

4)接下来,虚拟机要对对象进行必要的设置,例如对象头,对象头包括这个对象是哪个类的实例,如何才能找到类的元数据信息,对象的哈希吗,对象的GC分带年龄等信息。

5)以上步骤完成之后,对Java虚拟机而言创建对象就完成了。但对Java程序而言,创建对象的才刚刚开始。比如创建一个对象person,person对象中有成员变量name,age,sex,有构造器方法等信息,详细信息见下面的代码。

package cn.maoxiangyi.study.domain;

public class Person {
    private static String country = "中国";
    private String name;
    private int age;
    private String sex = "男";

    static {
        System.out.println("Static before country=" + country);
        country = "China";
        System.out.println("Static after country=" + country);
    }

    {
        System.out.println("Code Area before " + toString());
        age = 18;
        System.out.println("Code Area after " + toString());
    }

    public Person() {
    }

    public Person(String name, int age, String sex) {
        System.out.println("con after " + toString());
        this.name = name;
        this.age = age;
        this.sex = sex;
        System.out.println("con after " + toString());
    }

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}';
    }

    public static void main(String[] args) {
        System.out.println("create obj ");
        Person p = new Person("毛祥溢", 20, "男");
    }
}

这个类执行main方法后,依次的输出信息如下:

Static before country=中国
Static after country=China
create obj
Code Area before Person{name=’null’, age=0, sex=’男’}
Code Area after Person{name=’null’, age=18, sex=’男’}
con after Person{name=’null’, age=18, sex=’男’}
con after Person{name=’毛祥溢’, age=20, sex=’男’}

可以看到他们的执行顺序是:

1:在JVM中,静态成员变量country在类加载到方法区时就被赋值

2:在JVM中,方法区执行静态方法块,将country赋值为China

3: Java虚拟机执行main方法

4: Java创建对象,在内存中开辟空间,并将成员变量age对应的空间初始化为零。成员变量name对应的值初始化为null。

5:对象实例化会执行方法块,将age赋值为18。

6:最后执行到程序猿写的构造器,通过将name赋值为毛祥溢,age赋值为20。值此,整个类才初始化完毕。

Java专题(4)-Java的类加载机制

前言

由于博客没有备份,在一次莫名其妙的的事故中,丢失了之前所有的文章。根据本地文档和搜索引擎快照恢复了一些,但还有大部分文章永久性的丢失了。丢失文章的感觉就仿佛记忆被人抹去一块,明明知道她在哪里,搜遍脑海却是空白一片,心中不爽的很,所以打算从头再来,并借此机会系统的整理所学的知识。

Java的类加载机制

上一篇文章说道,Java虚拟机在创建对象的时候,首先就要检查这个类在常量池中对应的符号引用,并且检查这个符号引用的类是否已经被加载、解析和初始化过。如果没有就必须先执行类的加载过程。本篇文章就讨论下Java的类加载机制。

大多数人的Java之旅应该都是从Windows 命令行开始的,部署好Java的开发环境之后,就会学者写HelloWorld的代码,然后在命令行中输入: [java]java HelloWorld[/java] 命令执行后,JVM会将HelloWorld.class加载到内存中,并形成一个Class的对象HelloWorld.class。

类加载过程依次如下:

1:寻找jre目录,寻找jvm.dll,并初始化JVM;

2:产生一个Bootstrap Loader(启动类加载器)。 Bootstrap Loader 会加载System.getProperty(“sun.boot.class.path”)所指定的路径或jar。

3:Bootstrap Loader自动加载Extended Loader(标准扩展类加载器),并将其父Loader设为Bootstrap Loader。 Bootstrap Loader会加载System.getProperty(“java.ext.dirs”)所指定的路径或jar。

4:Bootstrap Loader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader。AppClass Loader会加载System.getProperty(“java.class.path”)所指定的路径或jar。

5:最后由AppClass Loader加载HelloWorld类。

类加载器的特点

1:运行一个程序时,总是由AppClass Loader(系统类加载器)开始加载指定的类。

2:在加载类时,每个类加载器会将加载任务上交给其父,如果其父找不到,再由自己去加

3:Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null.

案例验证

public class ClassLoaderDemo {

    public static void main(String[] args) {
        ClassLoaderDemo classLoaderDemo = new ClassLoaderDemo();
        System.out.println(classLoaderDemo.getClass().getClassLoader());
        System.out.println(classLoaderDemo.getClass().getClassLoader().getParent());
        System.out.println(classLoaderDemo.getClass().getClassLoader().getParent().getParent());
    }
}

 

输出的结果如下,可以看到他们的顺序依次是Bootstrap Loader、ExtClassLoader、AppClassLoader

[java]

sun.misc.Launcher$AppClassLoader@c4fe76

sun.misc.Launcher$ExtClassLoader@11e1e67

null

[/java]

除了供Java虚拟机使用的的类加载器之外,还有一个供程序员使用的类加载器URLClassLoader,通过URLClassLoader类加载器,程序猿可以在程序运行的时候加载相应的类。

提问的技术

在网络世界里,当提出一个技术问题时,你能得到怎样的回答?这取决于挖出答案的难度, 同样取决于你提问的方法。本指南旨在帮助你提高发问技巧,以获取你最想要的答案…… 这样一些人–他们不愿思考,或者在发问前不去完成他们应该做的事。这种人只会谋杀时间–他们只愿索取,从不付出,无端消耗我们的时间,而我们本可以把时间用在更有趣的问题或者更值得回答的人身上。

提问之前(Before You Ask) 在通过电邮、新闻组或者聊天室提出技术问题前,检查你有没有做到:

  • 1. 通读手册,试着自己找答案。
  • 2. 在FAQ里找答案(一份维护得好的FAQ可以包罗万象:)。
  • 3. 在网上搜索(个人推荐google~~~)。
  • 4. 向你身边精于此道的朋友打听。

怎样提问 (When You Ask) 谨慎选择论坛

小心选择提问的场合。如果象下面描述的那样,你很可能被忽略掉或者被看作失败者:

  • 1. 在风马牛不相及的论坛贴出你的问题
  • 2. 在探讨高级技巧的论坛张贴非常初级的问题;反之亦然
  • 3. 在太多的不同新闻组交叉张贴

精确描述,信息量大

  • 1. 谨慎明确的描述症状。
  • 2. 提供问题发生的环境(机器配置、操作系统、应用程序以及别的什么)。
  • 3. 说明你在提问前是怎样去研究和理解这个问题的。
  • 4. 说明你在提问前采取了什么步骤去解决它。
  • 5. 罗列最近做过什么可能有影响的硬件、软件变更。

案例:

蠢问题: 我在内核编译中一次又一次遇到SIG11错误,我怀疑某条飞线搭在主板的走线上了, 这种情况应该怎样检查最好?

聪明问题: 我自制的一套K6/233系统,主板是FIC-PA2007 (VIA Apollo VP2芯片组),256MB Corsair PC133 SDRAM,在内核编译中频频产生SIG11错误,从开机20分钟以后就有这种情况,开机前20分钟内从没发生过。重启也没有用,但是关机一晚上就又能工作20分钟。所有内存都换过了,没有效果。相关部分的典型编译记录如下…。

按时间顺序列出症状对找出问题最有帮助的线索,往往就是问题发生前的一系列操作,因此,你的说明应该包含操作步骤,以及电脑的反应,直到问题产生。 如果你的说明很长(超过四个段落),在开头简述问题会有所帮助,接下来按时间顺序详述。这样就会让人知道该在你的说明中找什么。

结尾: 问题结束后,一定概要反馈。不需要长篇的描述解决的过程,简单的反馈,既能表达感谢,也能为后来者提供思考。

PS:以上文章转自网络,并重新整合排版。

ZooKeeper使用小记

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。正因为如此,很多开源的系统也在使用ZooKeeper,包括MetaQ(全称Metamorphosis)、Strom、Jstorm也会使用到。

最早正式接触到ZooKeeper是因为要部署基于metaq+storm+redis的实时点击流处理系统,其中metaq和storm依赖ZooKeeper。哐哐哐部署完ZooKeeper后,又在网上看了一些分析ZooKeeper的选举、一致性的文章,后来业务上线之后,这个知识点就没有维护了(大部分人应该和我一样)。

最近项目中又需要搭建ZooKeeper,总结下比较常见的知识点:

知识点一:Error contacting service. It is probably not running.?

部署完成之后,运行zkServer.sh status 事,报Error contacting service. It is probably not running错误。

1:打开zkServer.sh 找到以下代码,在nc与localhost之间加上 -q 1 (是数字1而不是字母l)如果已存在则去掉

[shell] status) STAT=`echo stat | nc localhost $(grep clientPort “$ZOOCFG” | sed -e ‘s/.*=//’) 2> /dev/null| grep Mode` [/shell]

实践证明,在3.4.6的版本中并没有这段话,可能在以前的版本中有的。

2:配置文档里指定的log目录没有创建导致出错,手动增加目录后重启。

3:创建数据目录,也就是在你zoo.cfg配置文件里dataDir指定的那个目录下创建myid文件,并且指定id,改id为你zoo.cfg文件中server.1=localhost:2887:3887中的1.只要在myid头部写入1即可.

4:hostname和/etc/hosts文件中的信息不一致。

知识点二: /etc/zookeeper/conf/zoo.cfg 配置文件说明 配置文件的说明:

tickTime :基本事件单元,以毫秒为单位。这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。

dataDir :存储内存中数据库快照的位置,顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。

clientPort :这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

initLimit:这个配置项是用来配置 Zookeeper 接受客户端初始化连接时最长能忍受多少个心跳时间间隔数,当已经超过 5 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒。

syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒 server.A = B:C:D? ? ? A表示这个是第几号服务器,B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader。

知识点三:IOServerCnxn: Too many connections from …..

单个客户端与单台服务器之间的连接数的限制,是ip级别的,默认是60,如果设置为0,那么表明不作任何限制。请注意这个限制的使用范围,仅仅是单台客户端机器与单台ZK服务器之间的连接数限制,不是针对指定客户端IP,也不是ZK集群的连接数限制,也不是单台ZK对所有客户端的连接数限制。