﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-forrest-随笔分类-编程语言</title><link>http://www.cnitblog.com/forrest/category/4199.html</link><description>对过去我已无法选择，但令我稍感安慰的是我还拥有现在，所以。。。。。
更弥足珍贵</description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 07:58:52 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 07:58:52 GMT</pubDate><ttl>60</ttl><item><title>Java 中的堆和栈</title><link>http://www.cnitblog.com/forrest/archive/2008/12/16/52669.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Tue, 16 Dec 2008 03:25:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2008/12/16/52669.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/52669.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2008/12/16/52669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/52669.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/52669.html</trackback:ping><description><![CDATA[


<strong></strong><br><br>简单的说：<br>Java把内存划分成两种：一种是栈内存，一种是堆内存。 <br><br>&nbsp;&nbsp;
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。<embed src="http://www.xiami.com/widget/0_1769276040/singlePlayer.swf" type="application/x-shockwave-flash" width="257" height="33" wmode="transparent">加首歌have fun&#160;<br><br>&nbsp;&nbsp;
当在一段代码块定义一个变量时，Java就在栈中为这个变量分配内存空间，当超过变量的作用域后，Java会自动释放掉为该变量所分配的内存空间，该内存空间可以立即被另作他用。
<br><br>&nbsp;&nbsp; 堆内存用来存放由new创建的对象和数组。 <br><br>&nbsp;&nbsp; 在堆中分配的内存，由Java虚拟机的自动垃圾回收器来管理。
<br><br>&nbsp;&nbsp;
在堆中产生了一个数组或对象后，还可以在栈中定义一个特殊的变量，让栈中这个变量的取值等于数组或对象在堆内存中的首地址，栈中的这个变量就成了数组或对象的引用变量。
<br><br>&nbsp;&nbsp; 引用变量就相当于是为数组或对象起的一个名称，以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。
<br><br><br><br>&nbsp;&nbsp; &nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;<br><br>具体的说：<br>栈与堆都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。
<br>&nbsp;&nbsp; &nbsp;&nbsp;
Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等
指令建立，它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的，堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，因为它是在运行时
动态分配内存的，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。 <br>&nbsp;&nbsp; &nbsp;&nbsp;
栈的优势是，存取速度比堆要快，仅次于寄存器，栈数据可以共享。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。栈中主要存放一些基本
类型的变量（,int, short, long, byte, float, double, boolean, char）和对象句柄。 <br>&nbsp;&nbsp; &nbsp;&nbsp;
栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义： <br>int a = 3; <br>int b = 3； <br>编译器先处理int
a = 3；首先它会在栈中创建一个变量为a的引用，然后查找栈中是否有3这个值，如果没找到，就将3存放进来，然后将a指向3。接着处理int b =
3；在创建完b的引用变量后，因为在栈中已经有3这个值，便将b直接指向3。这样，就出现了a与b同时均指向3的情况。这时，如果再令a=4；那么编译器
会重新搜索栈中是否有4值，如果没有，则将4存放进来，并令a指向4；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这
种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的，因为这种情况a的修改并不会影响到b,
它是由编译器完成的，它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态，会影响到另一个对象引用变量。
<br><br>String是一个特殊的包装类数据。可以用： <br>String str = new String("abc"); <br>String
str = "abc"; <br>两种的形式来创建，第一种是用new()来新建对象的，它会在存放于堆中。每调用一次就会创建一个新的对象。
<br>而第二种是先在栈中创建一个对String类的对象引用变量str，然后查找栈中有没有存放"abc"，如果没有，则将"abc"存放进栈，并令str指向&#8221;abc&#8221;，如果已经有&#8221;abc&#8221;
则直接令str指向&#8220;abc&#8221;。 <br><br>&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
比较类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==，下面用例子说明上面的理论。 <br>String
str1 = "abc"; <br>String str2 = "abc"; <br>System.out.println(str1==str2);
//true <br>可以看出str1和str2是指向同一个对象的。 <br><br>String str1 =new String ("abc");
<br>String str2 =new String ("abc"); <br>System.out.println(str1==str2); //
false <br>用new的方式是生成不同的对象。每一次生成一个。 <br>&nbsp;&nbsp; 因此用第二种方式创建多个&#8221;abc&#8221;字符串,在内存中其实只存在一个对象而已.
这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String
str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。
<br>&nbsp;&nbsp; 另一方面, 要注意: 我们在使用诸如String str =
"abc"；的格式定义类时，总是想当然地认为，创建了String类的对象str。担心陷阱！对象可能并没有被创建！而可能只是指向一个先前已经创建的
对象。只有通过new()方法才能保证每次都创建一个新的对象。
由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。<br><br><br><br><br>java中内存分配策略及堆和栈的比较
<br>2.1 内存分配策略 <br>按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
<br>静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允
许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.
<br>栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知
的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知
的栈一样,栈式存储分配按照先进后出的原则进行分配。
<br>静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时
模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释 放.
<br><br>2.2 堆和栈的比较
<br>上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:
<br>从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的，栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:
<br>在编程中，例如C/C++中，所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶
向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack
Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候，修改栈指针就可以把栈中的内容销毁.这样的模式速度最快,
当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程
序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时.
<br>堆是应用程序在运行的时候请求操作系统分配给自己内存，由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间，因此用堆的效率非常低.但是堆的
优点在于,编译器不必知道要从堆里分配多少存储空间，也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面
向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中，要求创建一个对象时，只需用
new命令编制相关的代码即可。执行这些代码时，会在堆里自动进行数据的保存.当然，为达到这种灵活性，必然会付出一定的代价:在堆里分配存储空间时会花
掉更长的时间！这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).
<br><br><br>2.3 JVM中的堆和栈
<br>JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说，它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。
<br>我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的
Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译
原理中的活动纪录的概念是差不多的.
<br>从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域，该区域具有先进后出的特性。
<br>每一个Java应用都唯一对应一个JVM实例，每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程
共享.跟C/C++不同，Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的，但是这个对象的引用却是在堆栈中分配,也
就是说在建立一个对象时从两个地方都分配内存，在堆中分配的内存实际建立这个对象，而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。<br>2.4
GC的思考<br>Java为什么慢?JVM的存在当然是一个原因,但有人说,在Java中,除了简单类型(int,char等)的数据结构,其它都是在堆中分配内存(所以说Java的一切都是对象)，这也是程序慢的原因之一。<br>我的想法是(应该说代表TIJ的观点),如果没有Garbage
Collector(GC),上面的说法就是成立的.堆不象栈是连续的空间,没有办法指望堆本身的内存分配能够象堆栈一样拥有传送带般的速度,因为,谁会
为你整理庞大的堆空间,让你几乎没有延迟的从堆中获取新的空间呢?<br>这个时候,GC站出来解决问题.我们都知道GC用来清除内存垃圾,为堆腾出空间供程序使用,但GC同时也担负了另外一个重要的任务,就是要让Java中堆
的内存分配和其他语言中堆栈的内存分配一样快,因为速度的问题几乎是众口一词的对Java的诟病.要达到这样的目的,就必须使堆的分配也能够做到象传送带
一样,不用自己操心去找空闲空间.这样,GC除了负责清除Garbage外,还要负责整理堆中的对象,把它们转移到一个远离Garbage的纯净空间中无
间隔的排列起来,就象堆栈中一样紧凑,这样Heap
Pointer就可以方便的指向传送带的起始位置,或者说一个未使用的空间,为下一个需要分配内存的对象"指引方向".因此可以这样说,垃圾收集影响了对
象的创建速度,听起来很怪,对不对?<br>那GC怎样在堆中找到所有存活的对象呢?前面说了,在建立一个对象时，在堆中分配实际建立这个对象的内存,而在堆栈中分配一个指向这个堆对象的指针(引
用),那么只要在堆栈(也有可能在静态存储区)找到这个引用,就可以跟踪到所有存活的对象.找到之后,GC将它们从一个堆的块中移到另外一个堆的块中,并
将它们一个挨一个的排列起来,就象我们上面说的那样,模拟出了一个栈的结构,但又不是先进后出的分配,而是可以任意分配的,在速度可以保证的情况下, Isn't it
great?<br>但是，列宁同志说了,人的优点往往也是人的缺点,人的缺点往往也是人的优点(再晕~~).GC()的运行要占用一个线程,这本身就是一个降低程序运行性能
的缺陷,更何况这个线程还要在堆中把内存翻来覆去的折腾.不仅如此,如上面所说,堆中存活的对象被搬移了位置,那么所有对这些对象的引用都要重新赋值.这
些开销都会导致性能的降低.<br><br>
<p>基础数据类型直接在栈空间分配，方法的形式参数，直接在栈空间分配，当方法调用完成后从栈空间回收。引用数据类型，需要用new来创建，既在栈空间
分配一个地址空间，又在堆空间分配对象的类变量
。方法的引用参数，在栈空间分配一个地址空间，并指向堆空间的对象区，当方法调用完成后从栈空间回收。局部变量new出来时，在栈空间和堆空间中分配空
间，当局部变量生命周期结束后，栈空间立刻被回收，堆空间区域等待GC回收。方法调用时传入的literal参数，先在栈空间分配，在方法调用完成后从栈
空间分配。字符串常量在DATA区域分配，this在堆空间分配。数组既在栈空间分配数组名称，又在堆空间分配数组实际的大小！</p>
<p><strong>哦 对了，补充一下static在DATA区域分配。</strong></p>
<p>其实是有规律的，只要你理解了这些个基本的原理：</p>
<p><strong>堆空间的话</strong>：操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，会遍历该链表，寻找第一个空间大
于所申请空间的堆结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序。另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分
配的大小，这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重
新放入空闲链表中。是由new分配的内存，一般速度比较慢，而且容易产生内存碎片，不过用起来最方便。另外，在WINDOWS下，最好的方式是用
VirtualAlloc分配内存，他不是在堆，也不是在栈是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活。是向高地
址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小受
限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。</p>
<p><strong>栈空间的话</strong>：在Windows下,
栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的，在WINDOWS下，栈的大小是固定
的（是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将提示overflow。因此，能从栈获得的空间较小。只要栈的剩余空间大于所申请
空间，系统将为程序提供内存，否则将报异常提示栈溢出。 由系统自动分配，速度较快。但程序员是无法控制的。</p>
<p><strong>JVM中的堆和栈</strong></p>
<p>JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈。也就是说，对于一个Java程序来说，它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。</p>
<p>我们知道，某个线程正在执行的方法称为此线程的当前方法。我们可能不知道，当前方法使用的帧称为当前帧。当线程激活一个Java方法，JVM就会在
线程的Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间，这个帧将用来保存参数，局部变量，中间计算过程和其他数据。这个帧在这里
和编译原理中的活动纪录的概念是差不多的。</p>
<p>从Java的这种分配机制来看,堆栈又可以这样理解：堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域，该区域具有先进后出的特性。</p>
<p>每一个Java应用都唯一对应一个JVM实例，每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中，并由应用所有
的线程共享。跟C/C++不同，Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的，但是这个对象的引用却是在堆栈中分
配,也就是说在建立一个对象时从两个地方都分配内存，在堆中分配的内存实际建立这个对象，而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而 已。</p><img src ="http://www.cnitblog.com/forrest/aggbug/52669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2008-12-16 11:25 <a href="http://www.cnitblog.com/forrest/archive/2008/12/16/52669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在LINUX下配置JAVA开发环境</title><link>http://www.cnitblog.com/forrest/archive/2007/12/04/37310.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Tue, 04 Dec 2007 02:53:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2007/12/04/37310.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/37310.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2007/12/04/37310.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/37310.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/37310.html</trackback:ping><description><![CDATA[<h2 class="diaryTitle">在LINUX下配置JAVA开发环境- -</h2>
<p>&nbsp;转自&nbsp;&nbsp;&nbsp;<a  href="http://chenzhe.bokee.com/240643.html">http://chenzhe.bokee.com/240643.html</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
<p>折腾了一天,终于把Linux下的java开发环境配置好了,用的是RedHat Linux9.0 + JDK + Eclipse3 ,写出来共享.<br></p>
<p>1. 去http://java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK， <br>建议下载RPM自解压格式的（RPM in self-extracting file，j2sdk-1_4_2_06-linux-i586-rpm.bin）； <br>2. 上载到Linux服务器上，在shell下执行命令： <br>[root@LinuxServer rpm]# chmod 755 j2sdk-1_4_2_06-linux-i586-rpm.bin <br>[root@LinuxServer rpm]# ./j2sdk-1_4_2_06-linux-i586-rpm.bin <br><br>这时会有一段Sun的协议，敲几次空格键，当询问是否同意的时候，敲yes就可以了。 <br>Sun Microsystems, Inc. <br>Binary Code License Agreement <br>for the <br>JAVATM 2 SOFTWARE DEVELOPMENT KIT (J2SDK), STANDARD <br>EDITION, VERSION 1.4.2_X <br>... <br>Do you agree to the above license terms? [yes or no]yes <br>Unpacking... <br>Checksumming... <br>0 <br>0 <br>Extracting... <br>UnZipSFX 5.40 of 28 November 1998, by Info-ZIP (Zip-Bugs@lists.wku.edu). <br>inflating: j2sdk-1_4_2_06-linux-i586.rpm <br>Done. <br><br>注: 如果直接执行unzip命令来解压也是可以的,总之得到一个rpm软件包. <br><br>3. 程序会自动生成一个j2sdk-1_4_2_06-linux-i586.rpm文件，这是主程序包，下面来安装； <br>[root@LinuxServer rpm]#rpm -ivh j2sdk-1_4_2_06-linux-i586.rpm <br>Preparing... ########################################### [100%] <br>1:j2sdk ########################################### [100%] <br><br>4. 设置环境变量 <br>通常都喜欢用export命令直接在shell下设置 <br>[root@LinuxServer rpm]# export JAVA_HOME=/usr/java/j2sdk1.4.2_06 <br>[root@LinuxServer rpm]# export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar <br>[root@LinuxServer rpm]# export PATH=$PATH:$JAVA_HOME/bin <br><br><br>当然这样设置环境变量是可以生效的，但是只对当前shell生效。 <br>如果从另外一个shell登陆，将不能使用刚才设置的变量。所以最好的方法还是修改.bashrc文件。 <br>[root@LinuxServer rpm]#vi .bashrc <br>set JAVA_HOME=/usr/java/j2sdk1.4.2_06 <br>export JAVA_HOME <br>set PATH=$PATH:$JAVA_HOME/bin <br>export PATH <br>set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar <br>export CLASSPATH <br><br><br>当然也可以通过更改/etc/profile来实现，不过不推荐这么做， <br>因为这样的设置将对所以用户的shell都生效，对系统安全会产生影响。 <br>就是在这个文件的最后加上: <br>export JAVA_HOME=/usr/java/j2sdk1.4.2_06 <br>export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar <br>export PATH=$PATH:$JAVA_HOME/bin <br><br><br>下面来验证一下变量设置是否生效（####注意:在验证前先logout一下，再重新登陆）； <br>[root@LinuxServer rpm]# echo $JAVA_HOME <br>/usr/java/j2sdk1.4.2_06/ <br>[root@LinuxServer rpm]# echo $CLASSPATH <br>/usr/java/j2sdk1.4.2_06/lib/dt.jar:/usr/java/j2sdk1.4.2_06/lib/tools.jar <br>[root@LinuxServer rpm]# echo $PATH <br>/usr/java/j2sdk1.4.2_06/bin/:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin: <br>/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin <br>[root@LinuxServer rpm]# JAVA-version <br>JAVA version "1.4.2_06" <br>JAVA(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03) <br>JAVA HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode) <br><br>5. 环境设置OK，看看JDK是否能正常工作，我们来写一个测试文件test.java <br>[root@LinuxServer rpm]#vi test.java <br>class test <br>{ <br>public static void main(String[] args) <br>{ <br>System.out.println("Hello World!"); <br>} <br>} <br><br>保存退出，下面来编译、执行； <br>[root@LinuxServer text]# javac test.java <br>[root@LinuxServer text]# JAVA test <br>Hello World! <br><br>OK，工作正常。 <br>6. 如果要使某个用户具有运行java命令的权限，只要修改其bash初始化文件即可。 <br>比如要给用户longware以运行java命令的权限， <br>[root@LinuxServer root]# vi /home/longware/.bashrc <br>set JAVA_HOME=/usr/java/j2sdk1.4.2_06 <br>export JAVA_HOME <br>set PATH=$PATH:$JAVA_HOME/bin <br>export PATH <br>set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar <br>export CLASSPATH <br><br>7. 至此，Linux上JDK的安装完毕。下面安装eclipse-SDK-3.0-linux-gtk.zip <br>去www.eclipse.org下载一个eclipse3.0. 将eclipse-SDK-3.0-linux-gtk.zip解压到/opt中 <br><br>8、编写一个脚本用于启动eclipse <br><br>#!/bin/bash <br># <br># 执行 eclipse 3 <br># <br>export JAVA_HOME=/usr/java/j2sdk1.4.2_06 <br>export CLASSPATH=/usr/java/j2sdk1.4.2_06/lib <br>/opt/eclipse/eclipse -vm /usr/java/j2sdk1.4.2_06/bin/java -data /home/chenzhe/workspace ＆ <br># -vm 参数用以指定使用哪一个 jvm 来执行Eclipse， <br># -date参数用以指定Eclipse的数据目录。 <br>在此指定其存在用户根目录(/home/chenzhe/)下的workspace目录中 <br><br>将脚本保存到/usr/local/bin中，叫eclipse，并给eclipse分配755权限 <br><br>9、在桌面上创建一个启动器， <br>随便选一个图标,路径设置到/opt/eclipse/eclipse，/opt/eclipse/icon.xpm是eclipse自身带的图标. <br><br>10、双击图标,或者在终端输入eclipse, 搞定!</p><img src ="http://www.cnitblog.com/forrest/aggbug/37310.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-12-04 10:53 <a href="http://www.cnitblog.com/forrest/archive/2007/12/04/37310.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于eclipse 中导入插件的方法（links方法）</title><link>http://www.cnitblog.com/forrest/archive/2007/11/12/36181.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Mon, 12 Nov 2007 09:27:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2007/11/12/36181.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/36181.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2007/11/12/36181.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/36181.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/36181.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这是一种比较干净的导入方法，避免eclipse目录太臃肿&nbsp;&nbsp;<a href='http://www.cnitblog.com/forrest/archive/2007/11/12/36181.html'>阅读全文</a><img src ="http://www.cnitblog.com/forrest/aggbug/36181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-11-12 17:27 <a href="http://www.cnitblog.com/forrest/archive/2007/11/12/36181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java中四种操作xml方式的比较 (转)</title><link>http://www.cnitblog.com/forrest/archive/2007/11/04/35858.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Sun, 04 Nov 2007 14:34:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2007/11/04/35858.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/35858.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2007/11/04/35858.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/35858.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/35858.html</trackback:ping><description><![CDATA[<h2>java中四种操作xml方式的比较 (转)</h2>
<div class=t_msgfont id=postmessage_1461>1. 介绍<br><br>1）DOM(JAXP Crimson解析器) <br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DOM是用与平台和语言无关的方式表示<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=XML">XML</span><span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%CE%C4%B5%B5">文档</span>的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%BF%AA%B7%A2">开发</span>人员在树中寻找特定信息。分析该结构通常需要加载整个<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%CE%C4%B5%B5">文档</span>和构造层次结构，然后才能做任何工作。由于它是基于信息层次的，因而DOM被认为是基于树或基于<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%B6%D4%CF%F3">对象</span>的。DOM以及广义的基于树的处理具有几个优点。首先，由于树在内存中是持久的，因此可以修改它以便应用<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%B3%CC%D0%F2">程序</span>能对数据和结构作出更改。它还可以在任何时候在树中上下导航，而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。<br><br>2）SAX<br><br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;SAX处理的优点非常类似于流媒体的优点。分析能够立即开始，而不是等待所有的数据被处理。而且，由于应用程序只是在读取数据时检查数据，因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上，应用程序甚至不必解析整个文档；它可以在某个条件得到满足时停止解析。一般来说， SAX还比它的替代者DOM快许多。 <br>　　选择DOM还是选择SAX？ 对于需要自己编写代码来处理XML文档的开发人员来说，&nbsp;&nbsp;选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档，而SAX采用的事件模型。 <br><br>　　DOM解析器把XML文档转化为一个包含其内容的树，并可以对树进行遍历。用DOM解析模型的优点是编程容易，开发人员只需要调用建树的指令，然后利用navigation <span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=API">API</span>s访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档，所以对性能和内存的要求比较高，尤其是遇到很大的XML<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%CE%C4%BC%FE">文件</span>的时候。由于它的遍历能力，DOM解析器常用于XML文档需要频繁的改变的服务中。 <br><br>　　SAX解析器采用了基于事件的模型，它在解析XML文档的时候可以触发一系列的事件，当发现给定的tag的时候，它可以激活一个回调方法，告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低，因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时，SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难，而且很难同时访问同一个文档中的多处不同数据。 <br><br>3）JDOM&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<a href="http://www.jdom.org/" target=_blank><u><font color=#0000ff>http://www.jdom.org</font></u></a><br><br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; JDOM的目的是成为<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=Java">Java</span>特定文档模型，它简化与XML的交互并且比使用DOM实现更快。由于是第一个<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=Java">Java</span>特定模型，JDOM一直得到大力推广和促进。正在考虑通过&#8220;<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=Java">Java</span>规范请求JSR-102&#8221;将它最终用作&#8220;<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=Java">Java</span>标准扩展&#8221;。从2000年初就已经开始了JDOM开发。 <br><br>　　JDOM与DOM主要有两方面不同。首先，JDOM仅使用具体类而不使用接口。这在某些方面简化了API，但是也限制了灵活性。第二，API大量使用了Collections类，简化了那些已经熟悉这些类的Java开发者的使用。 <br><br>　　JDOM文档声明其目的是&#8220;使用20%(或更少)的精力解决80%(或更多)Java/XML问题&#8221;(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的，并且大多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而，它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。 <br><br>　　JDOM自身不包含解析器。它通常使用SAX2解析器来解析和<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%D1%E9%D6%A4">验证</span>输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%D4%B4%C2%EB">源码</span>。<br><br>4）DOM4J <a href="http://dom4j.sourceforge.net/" target=_blank><u><font color=#0000ff>http://dom4j.sourceforge.net</font></u></a> <br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; <br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;虽然DOM4J代表了完全独立的开发结果，但最初，它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能，包括集成的XPath 支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项，它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始，它就一直处于开发之中。 <br><br>　　为支持所有这些功能，DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类，但是在许多情况下，它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是，虽然DOM4J付出了更复杂的API的代价，但是它提供了比JDOM大得多的灵活性。 <br><br>　　在添加灵活性、XPath集成和对大文档处理的目标时，DOM4J的目标与JDOM是一样的：针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案，实现在本质上处理所有Java/XML问题的目标。在完成该目标时，它比JDOM更少强调防止不正确的应用程序行为。 <br><br>　　DOM4J是一个非常非常优秀的Java XML API，具有性能优异、功能强大和极端易用使用的特点，同时它也是一个开放<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=%D4%B4%B4%FA%C2%EB">源代码</span>的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML，特别值得一提的是连Sun的JAXM也在用DOM4J。 <br><br><br>2.. 比较<br><br>1）DOM4J性能最好，连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J，例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性，那就采用DOM4J.<br><br>2）JDOM和DOM在性能测试时表现不佳，在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题，但是从性能观点来看，它确实没有值得推荐之处。另外，DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础，因为它正式获得W3C推荐(与基于非标准的Java模型相对)，所以在某些类型的项目中可能也需要它(如在 JavaScript中使用DOM)。<br><br>3）SAX表现较好，这要依赖于它特定的解析方式－事件驱动。一个SAX检测即将到来的XML流，但并没有载入到内存(当然当XML流被读入时，会有部分文档暂时隐藏在内存中)。<br><br>3. 四种xml操作方式的基本使用方法<br><br>xml文件：<br><br>＜?xml version="1.0" encoding="GB2312"?＞<br>＜RESULT＞<br>&nbsp; &nbsp; ＜VALUE＞ <br>　　&nbsp; &nbsp;&nbsp; &nbsp;＜NO＞A1234＜/NO＞ <br>　　&nbsp; &nbsp;&nbsp;&nbsp;＜ADDR＞四川省XX县XX镇XX路X段XX号＜/ADDR＞<br>&nbsp; &nbsp; ＜/VALUE＞<br>&nbsp; &nbsp; ＜VALUE＞ <br>　　&nbsp; &nbsp;&nbsp; &nbsp;＜NO＞B1234＜/NO＞ <br>　&nbsp; &nbsp;&nbsp;&nbsp;　＜ADDR＞四川省XX市XX乡XX村XX组＜/ADDR＞<br>&nbsp; &nbsp; ＜/VALUE＞<br>＜/RESULT＞ <br><br>1）DOM<br><br><span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=import">import</span> java.io.*;<br>import java.<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=util">util</span>.*;<br>import org.w3c.dom.*;<br>import javax.xml.parsers.*; <br><br>public class MyXMLReader{ <br>　public static void main(String arge[]){ <br><br>　　long lasting =System.currentTimeMillis(); <br>　　try{&nbsp;&nbsp;<br>　　　File f=new File("data_10k.xml"); <br>　　　DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); <br>　　　DocumentBuilder builder=factory.newDocumentBuilder(); <br>　　　Document doc = builder.parse(f); <br>　　　Node<span class=t_tag onclick=tagshow(event) href="http://www.newwhy.com/tag.php?name=List">List</span> nl = doc.getElementsByTagName("VALUE"); <br>　　　for (int i=0;i＜nl.getLength();i++){ <br>　　　　System.out.print("车牌号码:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue()); <br>　　　　System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue()); <br>　 　} <br>　　}catch(Exception e){ <br>　　　e.printStackTrace(); <br>} <br><br>2）SAX<br><br>import org.xml.sax.*;<br>import org.xml.sax.helpers.*;<br>import javax.xml.parsers.*; <br><br>public class MyXMLReader extends DefaultHandler { <br><br>　java.util.Stack tags = new java.util.Stack(); <br>　public MyXMLReader() { <br>　　super();<br>&nbsp; &nbsp;} <br><br>　public static void main(String args[]) { <br>　　long lasting = System.currentTimeMillis(); <br>　　try { <br>　　　SAXParserFactory sf = SAXParserFactory.newInstance(); <br>　　　SAXParser sp = sf.newSAXParser(); <br>　　　MyXMLReader reader = new MyXMLReader(); <br>　　　sp.parse(new InputSource("data_10k.xml"), reader); <br>　　} catch (Exception e) { <br>　　　e.printStackTrace(); <br>　　} <br><br>　　System.out.println("运行时间：" + (System.currentTimeMillis() - lasting) + "毫秒");} <br>　　public void characters(char ch[], int start, int length) throws SAXException { <br>　　String tag = (String) tags.peek(); <br>　　if (tag.equals("NO")) {&nbsp;&nbsp;<br>　　　System.out.print("车牌号码：" + new String(ch, start, length));<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp; if (tag.equals("ADDR")) { <br>　　System.out.println("地址:" + new String(ch, start, length));<br>&nbsp; &nbsp; }<br>&nbsp; &nbsp;} <br><br>　　public void startElement(String uri,String localName,String qName,Attributes attrs) { <br>　　tags.push(qName);}<br>}&nbsp;&nbsp;<br><br>3） JDOM<br><br>import java.io.*;<br>import java.util.*;<br>import org.jdom.*;<br>import org.jdom.input.*; <br><br>public class MyXMLReader { <br><br>　public static void main(String arge[]) { <br>　　long lasting = System.currentTimeMillis(); <br>　　try { <br>　　　SAXBuilder builder = new SAXBuilder();&nbsp;&nbsp;<br>　　　Document doc = builder.build(new File("data_10k.xml"));&nbsp;&nbsp;<br>　　　Element foo = doc.getRootElement();&nbsp;&nbsp;<br>　　　List allChildren = foo.getChildren();&nbsp;&nbsp;<br>　　　for(int i=0;i＜allChildren.size();i++) {&nbsp;&nbsp;<br>　　　　System.out.print("车牌号码:" + ((Element)allChildren.get(i)).getChild("NO").getText()); <br>　　　　System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText()); <br>　　　} <br>　　} catch (Exception e) { <br>　　　e.printStackTrace(); <br>} <br><br>}<br><br>4）DOM4J<br><br>import java.io.*;<br>import java.util.*;<br>import org.dom4j.*;<br>import org.dom4j.io.*; <br><br>public class MyXMLReader { <br><br>　public static void main(String arge[]) { <br>　　long lasting = System.currentTimeMillis(); <br>　　try { <br>　　　File f = new File("data_10k.xml"); <br>　　　SAXReader reader = new SAXReader(); <br>　　　Document doc = reader.read(f); <br>　　　Element root = doc.getRootElement(); <br>　　　Element foo; <br>　　　for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) { <br>　　　　foo = (Element) i.next(); <br>　　　　System.out.print("车牌号码:" + foo.elementText("NO")); <br>　　　　System.out.println("车主地址:" + foo.elementText("ADDR")); <br>　　　} <br>　　} catch (Exception e) { <br>　　　e.printStackTrace(); <br>&nbsp; &nbsp; } <br>}<br><br><br>原文地址:<a href="http://blog.csdn.net/iori97king/archive/2007/07/24/1705894.aspx" target=_blank><u><font color=#0000ff>http://blog.csdn.net/iori97king/archive/2007/07/24/1705894.aspx</font></u></a></div>
<img src ="http://www.cnitblog.com/forrest/aggbug/35858.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-11-04 22:34 <a href="http://www.cnitblog.com/forrest/archive/2007/11/04/35858.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>防范SQL注入攻击</title><link>http://www.cnitblog.com/forrest/archive/2007/02/11/22937.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Sun, 11 Feb 2007 08:29:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2007/02/11/22937.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/22937.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2007/02/11/22937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/22937.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/22937.html</trackback:ping><description><![CDATA[Function SafeRequest(ParaName) <br />Dim ParaValue <br />ParaValue=Request(ParaName)<br />if IsNumeric(ParaValue) = True then<br />SafeRequest=ParaValue<br />exit Function<br />elseIf Instr(LCase(ParaValue),"select ") &gt; 0 or Instr(LCase(ParaValue),"insert ") &gt; 0 or Instr(LCase(ParaValue),"delete from") &gt; 0 or Instr(LCase(ParaValue),"count(") &gt; 0 or Instr(LCase(ParaValue),"drop table") &gt; 0 or Instr(LCase(ParaValue),"update ") &gt; 0 or Instr(LCase(ParaValue),"truncate ") &gt; 0 or Instr(LCase(ParaValue),"asc(") &gt; 0 or Instr(LCase(ParaValue),"mid(") &gt; 0 or Instr(LCase(ParaValue),"char(") &gt; 0 or Instr(LCase(ParaValue),"xp_cmdshell") &gt; 0 or Instr(LCase(ParaValue),"exec master") &gt; 0 or Instr(LCase(ParaValue),"net localgroup administrators") &gt; 0  or Instr(LCase(ParaValue)," and ") &gt; 0 or Instr(LCase(ParaValue),"net user") &gt; 0 or Instr(LCase(ParaValue)," or ") &gt; 0 then<br /> Response.Write "&lt;script language='javascript'&gt;"<br /> Response.Write "alert('非法的请求!');"  '发现SQL注入攻击提示信息<br /> Response.Write "location.href='http://www.wz114.com/';"  '发现SQL注入攻击转跳网址<br /> Response.Write "&lt;script&gt;"<br /> Response.end<br />else<br />SafeRequest=ParaValue<br />End If<br />End function<br /><br />使用SafeRequest函数替换你的Request<br /><br />可以防范所有的SQL注入攻击<img src ="http://www.cnitblog.com/forrest/aggbug/22937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-02-11 16:29 <a href="http://www.cnitblog.com/forrest/archive/2007/02/11/22937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>API(摘录)</title><link>http://www.cnitblog.com/forrest/archive/2007/01/05/21544.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Fri, 05 Jan 2007 05:17:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/archive/2007/01/05/21544.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/21544.html</wfw:comment><comments>http://www.cnitblog.com/forrest/archive/2007/01/05/21544.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/21544.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/21544.html</trackback:ping><description><![CDATA[
		<p>API是Application Programming Interface的缩写，是应用程序接口的意思，而3D API则是指显卡与应用程序直接的接口。3D API能让编程人员所设计的3D软件只要调用其API内的程序，从而让API自动和硬件的驱动程序沟通，启动3D芯片内强大的3D图形处理功能，从而大幅度地提高了3D程序的设计效率。</p>
		<p>如果没有3D API在开发程序时，程序员必须要了解全部的显卡特性，才能编写出与显卡完全匹配的程序，发挥出全部的显卡性能。而有了3D API这个显卡与软件直接的接口，程序员只需要编写符合接口的程序代码，就可以充分发挥显卡的不必再去了解硬件的具体性能和参数，这样就大大简化了程序开发的效率。</p>
		<p>同样，显示芯片厂商根据标准来设计自己的硬件产品，以达到在API调用硬件资源时最优化，获得更好的性能。有了3D API，便可实现不同厂家的硬件、软件最大范围兼容。比如在最能体现3D API的游戏方面，游戏设计人员设计时，不必去考虑具体某款显卡的特性，而只是按照3D API的接口标准来开发游戏，当游戏运行时则直接通过3D API来调用显卡的硬件资源。</p>
		<p>目前个人电脑中主要应用的3D API有DirectX和OpenGL。</p>
		<p>DirectX</p>
		<p>DirectX并不是一个单纯的图形API，它是由微软公司开发的用途广泛的API，它包含有Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多个组件，它提供了一整套的多媒体接口方案。只是其在3D图形方面的优秀表现，让它的其它方面显得暗淡无光。DirectX开发之初是为了弥补Windows 3.1系统对图形、声音处理能力的不足，而今已发展成为对整个多媒体系统的各个方面都有决定性影响的接口。</p>
		<p>DirectX 1.0<br />第一代的DirectX很不成功，推出时众多的硬件均不支持，当时基本都采用专业图形API－OpenGL，缺乏硬件的支持成了其流行的最大障碍。<br />DirectX 1.0版本是第一个可以直接对硬件信息进行读取的程序。它提供了更为直接的读取图形硬件的性能（比如：显示卡上的块移动功能）以及基本的声音和输入设备功能（函数），使开发的游戏能实现对二维（2D）图像进行加速。这时候的DirectX不包括现在所有的3D功能，还处于一个初级阶段。</p>
		<p>DirectX 2.0<br />DirectX 2.0在二维图形方面做了些改进，增加了一些动态效果，采用了Direct 3D的技术。这样DirectX 2.0与DirectX 1.0有了相当大的不同。在DirectX 2.0中，采用了“平滑模拟和RGB模拟”两种模拟方式对三维(3D)图像进行加速计算的。DirectX 2.0同时也采用了更加友好的用户设置程序并更正了应用程序接口的许多问题。从DirectX 2.0开始，整个DirectX的设计架构雏形就已基本完成。</p>
		<p>DirectX 3.0<br />DirectX 3.0的推出是在1997年最后一个版本的Windows95发布后不久，此时3D游戏开始深入人心，DirectX也逐渐得到软硬件厂商的认可。97年时应用程序接口标准共有三个，分别是专业的OpenGL接口，微软的DirectX D接口和3DFX公司的Glide接口。而那时的3DFX公司是最为强大的显卡制造商，它的Glide接口自然也受到最广泛的应用，但随着3DFX公司的没落，Voodoo显卡的衰败，Glide接口才逐渐消失了。</p>
		<p>DirectX 3.0是DirectX 2.0的简单升级版，它对DirectX 2.0的改动并不多。包括对DirectSound（针对3D声音功能）和DirectPlay（针对游戏/网络）的一些修改和升级。DirectX 3.0集成了较简单的3D效果，还不是很成熟。</p>
		<p>DirectX 5.0<br />微软公司并没有推出DirectX 4.0，而是直接推出了DirectX 5.0。此版本对Direct3D做出了很大的改动，加入了雾化效果、Alpha混合等3D特效，使3D游戏中的空间感和真实感得以增强，还加入了S3的纹理压缩技术。<br />同时，DirectX 5.0在其它各组件方面也有加强，在声卡、游戏控制器方面均做了改进，支持了更多的设备。因此，DirectX发展到DirectX 5.0才真正走向了成熟。此时的DirectX性能完全不逊色于其它3D API，而且大有后来居上之势。</p>
		<p>DirectX 6.0<br />DirectX 6.0推出时，其最大的竞争对手之一Glide，已逐步走向了没落，而DirectX则得到了大多数厂商的认可。DirectX 6.0中加入了双线性过滤、三线性过滤等优化3D图像质量的技术，游戏中的3D技术逐渐走入成熟阶段。</p>
		<p>DirectX 7.0<br />DirectX 7.0最大的特色就是支持T&amp;L，中文名称是“坐标转换和光源”。3D游戏中的任何一个物体都有一个坐标，当此物体运动时，它的坐标发生变化，这指的就是坐标转换；3D游戏中除了场景＋物体还需要灯光，没有灯光就没有3D物体的表现，无论是实时3D游戏还是3D影像渲染，加上灯光的3D渲染是最消耗资源的。虽然OpenGL中已有相关技术，但此前从未在民用级硬件中出现。</p>
		<p>在T&amp;L问世之前，位置转换和灯光都需要CPU来计算，CPU速度越快，游戏表现越流畅。使用了T&amp;L功能后，这两种效果的计算用显示卡的GPU来计算，这样就可以把CPU从繁忙的劳动中解脱出来。换句话说，拥有T&amp;L显示卡，使用DirectX 7.0，即使没有高速的CPU，同样能流畅的跑3D游戏。</p>
		<p>DirectX 8.0<br />DirectX 8.0的推出引发了一场显卡革命，它首次引入了“像素渲染”概念，同时具备像素渲染引擎(Vertex Shader)与顶点渲染引擎(Pixel Shader)，反映在特效上就是动态光影效果。同硬件T&amp;L仅仅实现的固定光影转换相比，VS和PS单元的灵活性更大，它使GPU真正成为了可编程的处理器。这意味着程序员可通过它们实现3D场景构建的难度大大降低。通过VS和PS的渲染，可以很容易的宁造出真实的水面动态波纹光影效果。此时DirectX的权威地位终于建成。</p>
		<p>DirectX 9.0<br />2002年底，微软发布DirectX9.0。DirectX 9中PS单元的渲染精度已达到浮点精度，传统的硬件T&amp;L单元也被取消。全新的VertexShader(顶点着色引擎)编程将比以前复杂得多，新的VertexShader标准增加了流程控制，更多的常量，每个程序的着色指令增加到了1024条。</p>
		<p>PS 2.0具备完全可编程的架构，能对纹理效果即时演算、动态纹理贴图，还不占用显存，理论上对材质贴图的分辨率的精度提高无限多；另外PS1.4只能支持28个硬件指令，同时操作6个材质，而PS2.0却可以支持160个硬件指令，同时操作16个材质数量，新的高精度浮点数据规格可以使用多重纹理贴图，可操作的指令数可以任意长，电影级别的显示效果轻而易举的实现。</p>
		<p>VS 2.0通过增加Vertex程序的灵活性，显著的提高了老版本(DirectX8)的VS性能，新的控制指令，可以用通用的程序代替以前专用的单独着色程序，效率提高许多倍；增加循环操作指令，减少工作时间，提高处理效率；扩展着色指令个数，从128个提升到256个。</p>
		<p>增加对浮点数据的处理功能，以前只能对整数进行处理，这样提高渲染精度，使最终处理的色彩格式达到电影级别。突破了以前限制PC图形图象质量在数学上的精度障碍，它的每条渲染流水线都升级为128位浮点颜色，让游戏程序设计师们更容易更轻松的创造出更漂亮的效果，让程序员编程更容易。</p>
		<p>显卡所支持的DirectX版本已成为评价显卡性能的标准，从显卡支持什么版本的DirectX，用户就可以分辨出显卡的性能高低，从而选择出适合于自己的显卡产品。</p>
		<p>OpenGL</p>
		<p>OpenGL是个专业的3D程序接口，是一个功能强大，调用方便的底层3D图形库。OpenGL的前身是SGI公司为其图形工作站开发的IRIS GL。IRIS GL是一个工业标准的3D图形软件接口，功能虽然强大但是移植性不好，于是SGI公司便在IRIS GL的基础上开发了OpenGL。OpenGL的英文全称是“Open Graphics Library”，顾名思义，OpenGL便是“开放的图形程序接口”。虽然DirectX在家用市场全面领先，但在专业高端绘图领域，OpenGL是不能被取代的主角。</p>
		<p>OpenGL是个与.硬件无关的软件接口，可以在不同的平台如Windows 95、Windows NT、Unix、Linux、MacOS、OS／2之间进行移植。因此，支持OpenGL的软件具有很好的移植性，可以获得非常广泛的应用。由于OpenGL是3D图形的底层图形库，没有提供几何实体图元，不能直接用以描述场景。但是，通过一些转换程序，可以很方便地将AutoCAD、3DS等3D图形设计软件制作的DFX和3DS模型文件转换成OpenGL的顶点数组。</p>
		<p>在OpenGL的基础上还有Open Inventor、Cosmo3D、Optimizer等多种高级图形库，适应不同应用。其中，Open Inventor应用最为广泛。该软件是基于OpenGL面向对象的工具包，提供创建交互式3D图形应用程序的对象和方法，提供了预定义的对象和用于交互的事件处理模块，创建和编辑3D场景的高级应用程序单元，有打印对象和用其它图形格式交换数据的能力。</p>
		<p>OpenGL的发展一直处于一种较为迟缓的态势，每次版本的提高新增的技术很少，大多只是对其中部分做出修改和完善。1992年7月，SGI公司发布了OpenGL的1.0版本，随后又与微软公司共同开发了Windows NT版本的OpenGL，从而使一些原来必须在高档图形工作站上运行的大型3D图形处理软件也可以在微机上运用。1995年OpenGL的1.1版本面市，该版本比1.0的性能有许多提高，并加入了一些新的功能。其中包括改进打印机支持，在增强元文件中包含OpenGL的调用，顶点数组的新特性，提高顶点位置、法线、颜色、色彩指数、纹理坐标、多边形边缘标识的传输速度，引入了新的纹理特性等等。OpenGL 1.5又新增了“OpenGL Shading Language”，该语言是“OpenGL 2.0”的底核，用于着色对象、顶点着色以及片断着色技术的扩展功能。</p>
		<p>OpenGL 2.0标准的主要制订者并非原来的SGI，而是逐渐在ARB中占据主动地位的3Dlabs。2.0版本首先要做的是与旧版本之间的完整兼容性，同时在顶点与像素及内存管理上与DirectX共同合作以维持均势。OpenGL 2.0将由OpenGL 1.3的现有功能加上与之完全兼容的新功能所组成(如图一)。借此可以对在ARB停滞不前时代各家推出的各种纠缠不清的扩展指令集做一次彻底的精简。此外，硬件可编程能力的实现也提供了一个更好的方法以整合现有的扩展指令。</p>
		<p>目前，随着DirectX的不断发展和完善，OpenGL的优势逐渐丧失，至今虽然已有3Dlabs提倡开发的2.0版本面世，在其中加入了很多类似于DirectX中可编程单元的设计，但厂商的用户的认知程度并不高，未来的OpenGL发展前景迷茫。<br /></p>
<img src ="http://www.cnitblog.com/forrest/aggbug/21544.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-01-05 13:17 <a href="http://www.cnitblog.com/forrest/archive/2007/01/05/21544.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>