Fantasy's World

世界的小世界,我的大世界^_^

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  6 Posts :: 0 Stories :: 16 Comments :: 0 Trackbacks

2005年12月29日 #

首先看看我写的一个小程序:

public class TestTry extends Exception
{
 static boolean f=false;
 static int sum=0;
 static int created=0;
 static int i=0;
 TestTry()
 {
  i=created++;
  if(created>=299) f=true;
  }
 public void finalize()
 {
  sum++;
  }
 public static void main(String[] args)
 {
  while(!TestTry.f)
  {
   try{
    throw new TestTry();
    }catch(Exception e){}
    finally{
     System.out.println("Creat "+TestTry.i+" TestTry, "+TestTry.sum+" has been finalized!");
     }
    }
  //System.out.println("Creat "+TestTry.created+" TestTry, "+TestTry.sum+" has been finalized!"); 
  }
 }

这个是我在测试在try语句抛出异常后,在try语句中建立的对象是否会调用自身的终止函数时发现的,这里有个奇怪的现象在if(created>=299) f=true;这条语句中,如果把条件created>=299改为>=比299更大的数,你会发现System.out.println("Creat "+TestTry.i+" TestTry, "+TestTry.sum+" has been finalized!");这条语句的输出的结果并不是你预想的那样(输出判断的数字+1的行数),而只是显示最后的三百行。那么在这之前抛出的异常上哪里去了呢?难道说Java只处理最后抛出的三百的异常么?
posted @ 2005-12-29 18:21 FinalFantasy 阅读(285) | 评论 (0)编辑 收藏

2005年12月26日 #

这个文档是老师给我们看的,看了之后收获不少,帖出来让大家也看看:)

引言

Java的堆是一个运行时数据区,类的实例(对象)从中分配空间。Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过newnewarrayanewarraymultianewarray等指令建立,但是它们不需要程序代码来显式地释放。一般来说,堆的是由垃圾回收 来负责的,尽管JVM规范并不要求特殊的垃圾回收技术,甚至根本就不需要垃圾回收,但是由于内存的有限性,JVM在实现的时候都有一个由垃圾回收所管理的堆。垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能。

垃圾收集的意义

C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。

垃圾收集能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾收集机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程的时候,靠垃圾收集机制可大大缩短时间。其次是它保护程序的完整性, 垃圾收集是Java语言安全性策略的一个重要部份。

垃圾收集的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象, 而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾收集算法的不完备性,早先采用的某些垃圾收集算法就不能保证100%收集到所有的废弃内存。当然随着垃圾收集算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。

垃圾收集的算法分析

Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾收集算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。

大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就量正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首选需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。下面介绍几个常用的算法。

1、  引用计数法(Reference Counting Collector)

引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须 实时运行的程序。但引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1

2tracing算法(Tracing Collector)

tracing算法是为了解决引用计数法的问题而提出,它使用了根集的概念。基于tracing算法的垃圾收集器从根集开始扫描,识别出哪些对象可达,哪些对象不可达,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。在扫描识别过程中,基于tracing算法的垃圾收集也称为标记和清除(mark-and-sweep)垃圾收集器.

3compacting算法(Compacting Collector)

为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来 的对象。在基于Compacting算法的收集器的实现中,一般增加句柄和句柄表。  

4copying算法(Coping Collector)

该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象 面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于coping算法的垃圾 收集就从根集中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。

一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象面和空闲区域面,在对象面与空闲区域面的切换过程中,程序暂停执行。

5generation算法(Generational Collector)
  stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代(generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。

6adaptive算法(Adaptive Collector)

在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。

透视Java垃圾回收

1、命令行参数透视垃圾收集器的运行

2、使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求Java的垃圾回收。在命令行中有一个参数-verbosegc可以查看Java使用的堆内存的情况,它的格式如下:

java -verbosegc classfile

  可以看个例子:

class TestGC
{
 public static void main(String[] args)
 {
  new TestGC();
  System.gc();
  System.runFinalization();
 }
}


  在这个例子中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为可达,程序编译后,执行命令: java -verbosegc TestGC 后结果为:

[Full GC 168K->97K(1984K), 0.0253873 secs]

  机器的环境为,Windows 2000 + JDK1.3.1,箭头前后的数据168K97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)。

  2finalize方法透视垃圾收集器的运行

  在JVM垃圾收集器收集一个对象之前 ,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止化该对象心释放资源,这个方法就是finalize()。它的原型为:

protected void finalize() throws Throwable

  在finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。

  之所以要使用finalize(),是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C风格的事情。这主要可以通过"固有方法"来进行,它是从Java里调用非Java方法的一种方式。CC++是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序,所以能够有效地调用任何东西。在非Java代码内部,也许能调用Cmalloc()系列函数,用它分配存储空间。而且除非调用了free(),否则存储空间不会得到释放,从而造成内存"漏洞"的出现。当然,free()是一个CC++函数,所以我们需要在finalize()内部的一个固有方法中调用它。也就是说我们不能过多地使用finalize(),它并不是进行普通清除工作的理想场所。

  在普通的清除工作中,为清除一个对象,那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与C++"破坏器"的概念稍有抵触。在C++中,所有对象都会破坏(清除)。或者换句话说,所有对象都"应该"破坏。若将C++对象创建成一个本地对象,比如在堆栈中创建(在Java中是不可能的),那么清除或破坏工作就会在"结束花括号"所代表的、创建这个对象的作用域的末尾进行。若对象是用new创建的(类似于Java),那么当程序员调用C++delete命令时(Java没有这个命令),就会调用相应的破坏器。若程序员忘记了,那么永远不会调用破坏器,我们最终得到的将是一个内存"漏洞",另外还包括对象的其他部分永远不会得到清除。

  相反,Java不允许我们创建本地(局部)对象--无论如何都要使用new。但在Java中,没有"delete"命令来释放对象,因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场,我们可以说正是由于存在垃圾收集机制,所以Java没有破坏器。然而,随着以后学习的深入,就会知道垃圾收集器的存在并不能完全消除对破坏器的需要,或者说不能消除对破坏器代表的那种机制的需要(而且绝对不能直接调用finalize(),所以应尽量避免用它)。若希望执行除释放存储空间之外的其他某种形式的清除工作,仍然必须调用Java中的一个方法。它等价于C++的破坏器,只是没后者方便。

  下面这个例子向大家展示了垃圾收集所经历的过程,并对前面的陈述进行了总结。

class Chair {
 static boolean gcrun = false;
 static boolean f = false;
 static int created = 0;
 static int finalized = 0;
 int i;
 Chair() {
  i = ++created;
  if(created == 47)
   System.out.println("Created 47");
 }
 protected void finalize() {
  if(!gcrun) {
   gcrun = true;
   System.out.println("Beginning to finalize after " + created + " Chairs have been created");
  }
  if(i == 47) {
   System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");
   f = true;
  }
  finalized++;
  if(finalized >= created)
   System.out.println("All " + finalized + " finalized");
 }
}

public class Garbage {
 public static void main(String[] args) {
  if(args.length == 0) {
   System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");
   return;
  }
  while(!Chair.f) {
   new Chair();
   new String("To take up space");
  }
  System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +
", total finalized = " + Chair.finalized);
  if(args[0].equals("before")) {
    System.out.println("gc():");
    System.gc();
    System.out.println("runFinalization():");
    System.runFinalization();
  }
  System.out.println("bye!");
  if(args[0].equals("after"))
   System.runFinalizersOnExit(true);
 }
}


  上面这个程序创建了许多Chair对象,而且在垃圾收集器开始运行后的某些时候,程序会停止创建Chair。由于垃圾收集器可能在任何时间运行,所以我们不能准确知道它在何时启动。因此,程序用一个名为gcrun的标记来指出垃圾收集器是否已经开始运行。利用第二个标记fChair可告诉main()它应停止对象的生成。这两个标记都是在finalize()内部设置的,它调用于垃圾收集期间。另两个static变量--created以及finalized--分别用于跟踪已创建的对象数量以及垃圾收集器已进行完收尾工作的对象数量。最后,每个Chair都有它自己的(非staticint i,所以能跟踪了解它具体的编号是多少。编号为47Chair进行完收尾工作后,标记会设为true,最终结束Chair对象的创建过程。(关于这个例子的更具体的分析和说明请参看《Java编程思想》的第四章)

  关于垃圾收集的几点补充

  经过上述的说明,可以发现垃圾回收有以下的几个特点:

  (1)垃圾收集发生的不可预知性:由于实现了不同的垃圾收集算法和采用了不同的收集机制,所以它有可能是定时发生,有可能是当出现系统空闲CPU资源时发生,也有可能是和原始的垃圾收集一样,等到内存消耗出现极限时发生,这与垃圾收集器的选择和具体的设置都有关系。

  (2)垃圾收集的精确性:主要包括2 个方面:(a)垃圾收集器能够精确标记活着的对象;(b)垃圾收集器能够精确地定位对象之间的引用关系。前者是完全地回收所有废弃对象的前提,否则就可能造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收,所有对象都能够重新分配,允许对象的复制和对象内存的缩并,这样就有效地防止内存的支离破碎。(3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异,既有当垃圾收集开始时就停止应用程序的运行,又有当垃圾收集开始时也允许应用程序的线程运行,还有在同一时间垃圾收集多线程运行。

  (4)垃圾收集的实现和具体的JVM 以及JVM的内存模型有非常紧密的关系。不同的JVM 可能采用不同的垃圾收集,而JVM 的内存模型决定着该JVM可以采用哪些类型垃圾收集。现在,HotSpot 系列JVM中的内存系统都采用先进的面向对象的框架设计,这使得该系列JVM都可以采用最先进的垃圾收集。

  (5)随着技术的发展,现代垃圾收集技术提供许多可选的垃圾收集器,而且在配置每种收集器的时候又可以设置不同的参数,这就使得根据不同的应用环境获得最优的应用性能成为可能。

  针对以上特点,我们在使用的时候要注意:

  (1)不要试图去假定垃圾收集发生的时间,这一切都是未知的。比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存就可以被释放。

  (2Java中提供了一些和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。

  (3)挑选适合自己的垃圾收集器。一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。否则可以考虑使用有针对性的垃圾收集器,比如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考虑使用并行标记/清除收集器。

  (4)关键的也是难把握的问题是内存泄漏。良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。

  (5)尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。

  结束语

  一般来说,Java开发人员可以不重视JVM中堆内存的分配和垃圾处理收集,但是,充分理解Java的这一特性可以让我们更有效地利用资源。同时要注意finalize()方法是Java的缺省机制,有时为确保对象资源的明确释放,可以编写自己的finalize方法。

 

 

 

posted @ 2005-12-26 17:46 FinalFantasy 阅读(1132) | 评论 (2)编辑 收藏

2005年12月21日 #

Problem Statement

You are given a String[] cityMap representing the layout of a city. The city consists of blocks. The first element of cityMap represents the first row of blocks, etc. A 'B' character indicates a location where there is a bus stop. There will be exactly one 'X' character, indicating your location. All other characters will be '.'. You are also given an int walkingDistance, which is the maximum distance you are willing to walk to a bus stop. The distance should be calculated as the number of blocks vertically plus the number of blocks horizontally. Return the number of bus stops that are within walking distance of your current location.

Definition

Class:BusStops
Method:countStops
Parameters:String[], int
Returns:int
Method signature:int countStops(String[] cityMap, int walkingDistance)
(be sure your method is public)

Constraints

-cityMap will contain between 1 and 50 elements, inclusive.
-Each element of cityMap will contain between 1 and 50 characters, inclusive.
-Each element of cityMap will contain the same number of characters.
-Each character of each element of cityMap will be 'B', 'X', or '.'.
-There will be exactly one 'X' character in cityMap.
-walkingDistance will be between 1 and 100, inclusive.

Examples

0)

{"...B.",
 ".....",
 "..X.B",
 ".....",
 "B...."}
3
Returns: 2
You can reach the bus stop at the top (3 units away), or on the right (2 units away). The one in the lower left is 4 units away, which is too far.

1)

{"B.B..",
 ".....",
 "B....",
 ".....",
 "....X"}
8
Returns: 3
A distance of 8 can get us anywhere on the map, so we can reach all 3 bus stops.

2)

{"BBBBB",
 "BB.BB",
 "B.X.B",
 "BB.BB",
 "BBBBB"}
1
Returns: 0
Plenty of bus stops, but unfortunately we cannot reach any of them.

3)

{"B..B..",
 ".B...B",
 "..B...",
 "..B.X.",
 "B.B.B.",
 ".B.B.B"}
3
Returns: 7


说实话我觉得这一题没啥意思,超简单,首先先确定X的位置,再用遍历数组找B的位置,再求相减的绝对值然后判断是否超出给出的最大距离就行了。相对这题PlayCars却很有意思,到现在我也没想出除了穷举以外的一个更好的算法,因为我觉得穷举可能会超时。有哪位有其它的办法的话,请告诉我,大家探讨一下,谢谢。好了,不废话了,下面是这题的答案:

public class BusStops {
 public static void main(String[] arg){
  BusStops total = new BusStops();
  
    System.out.println(total.countStops({"...B.",".....","..X.B",".....","B...."},3));
 }
 
 public int countStops(String[] cityMap, int walkingDistance){
  int sum= 0;
  int locationX = -1;
  int locationY = -1;
  for(int i=0;i<cityMap.length;i++){
   for(int j=0;j<cityMap[i].length();j++){
    if(cityMap[i].charAt(j)=='X'){
     locationX = i;
     locationY = j;
    }
   }
  }
  for(int i=0;i<cityMap.length;i++){
   for(int j=0;j<cityMap[i].length();j++){
    if(cityMap[i].charAt(j)=='B' && (Math.abs(locationX - i) + Math.abs(locationY - j)<=walkingDistance))
     sum++;
   }
  }
  return sum;
 }
}
posted @ 2005-12-21 18:24 FinalFantasy 阅读(553) | 评论 (1)编辑 收藏

2005年12月14日 #

Problem Statement

 

    

When a stone is thrown across water, sometimes it will land on the water and bounce rather than falling in right away. Suppose that a stone is thrown a distance of n. On each successive bounce it will travel half the distance as the previous bounce (rounded down to the nearest integer). When it can not travel any further, it falls into the water. If, at any point, the stone lands on an obstruction rather than water, it will not bounce, but will simply deflect and fall into the water. Please look at the figure for further clarification (with black, red and green cells representing banks, obstructions and free water respectively). So, if the stone is thrown a distance 7, it will bounce and travel a distance of 3, then finally a distance of 1, having travelled a total distance of 11 (the green path in the figure). If a stone is thrown a distance of 8, it will reach the opposite bank, and if thrown at distances of 2 or 6 it will hit an obstruction during its travel. These are the three red paths in the figure.



You are given a String water. An 'X' represents an obstruction, while a '.' represents water free from obstruction. You are to return an int representing the maximum distance a stone can travel and finally fall in the water, without hitting any obstructions, and without reaching the opposite bank (going beyond the end of the string). You may choose any initial distance for the throw, which starts from the left side of the string. A distance of 1 is the first character of the string, etc. If no initial throw will result in the stone landing in the water without hitting an obstruction, return 0.

Definition

    

Class:

SkipStones

Method:

maxDistance

Parameters:

String

Returns:

int

Method signature:

int maxDistance(String water)

(be sure your method is public)

    

 

 

 

Notes

-

Obstructions are at water level, so the stone will not hit any obstructions while it's in the air.

Constraints

-

water will contain between 1 and 50 elements, inclusive.

-

Each element of water will contain between 1 and 50 characters, inclusive.

-

Each character of each element of water will be 'X' or '.'.

Examples

0)

 

    

"..X.....X..."

Returns: 11

This is the example from the problem statement.

1)

 

    

"...X..."

Returns: 3

If it weren't for the obstruction, we could start with a throw of distance 4, and go a total of 7. But, the best we can do is to throw the stone a distance of 2, and have it skip a distance of 1.

2)

 

    

"....X....X...XXXX.X....."

Returns: 22

12 + 6 + 3 + 1 = 22, is the best case.

3)

 

    

"XXXXXXX.XXX.X.."

Returns: 15

Here, an initial throw of 8 is the only way to avoid hitting an obstruction. Notice that the stone finally falls in the water just before reaching the opposite bank.

 

 


这次的题目可以说并不是太难,也许很多人被全英文的题目给难住了,其实并不应该。像我这个还没过CET4的人都能看得懂,何况是大家呢:)好了,废话不多说了,下面是我写的答案:

public class SkipStones
{
 public int sum;
 public int total;
 public int maxDistance(String water)
 {
  for(int i=water.length();i>0;i--)
  {
   total=0;
   sum=0;
   int j=i;
   do
   {
    sum+=j;
    j/=2;
    }while(j!=0);
   if(sum>water.length()) continue;
   else
   {
    j=i;
    int b=j-1;
    while(j!=0)
    {
     if(water.charAt(b)=='X') break;
     else
     {
      total+=j;
      j/=2;
      b+=j;
      }
     }
    }
    if(total==sum) break;
   }
   if(total==sum) return sum;
   else return 0;
  }
  
  
 public static void main(String[] args)
 {
  SkipStones a=new SkipStones();
  System.out.println("The maxdistance is "+a.maxDistance("..X.....X..."));
  }
 }
posted @ 2005-12-14 16:32 FinalFantasy 阅读(1462) | 评论 (5)编辑 收藏

2005年11月1日 #

《thinking in java》中一段代码剖析

程序代码

//chapter03:Garbage.java

// Demonstration of the garbage

// collector and finalization

class Chair {

  static boolean gcrun = false;

  static boolean f = false;

  static int created = 0;

  static int finalized = 0;

  int i;

  Chair() {

    i = ++created;

    if(created == 47)

      System.out.println("Created 47");

  }

  public void finalize() {

    if(!gcrun) {

      // The first time finalize() is called:

      gcrun = true;

      System.out.println(

        "Beginning to finalize after " +

        created + " Chairs have been created");

    }

    if(i == 47) {

      System.out.println(

        "Finalizing Chair #47, " +

        "Setting flag to stop Chair creation");

      f = true;

    }

    finalized++;

    if(finalized >= created)

      System.out.println(

        "All " + finalized + " finalized");

  }

}

public class Garbage {

  public static void main(String[] args) {

    // As long as the flag hasn't been set,

    // make Chairs and Strings:

    while(!Chair.f) {

      new Chair();

      new String("To take up space");

    }

    System.out.println(

      "After all Chairs have been created:\n" +

      "total created = " + Chair.created +

      ", total finalized = " + Chair.finalized);

    // Optional arguments force garbage

    // collection & finalization:

    if(args.length > 0) {

      if(args[0].equals("gc") &line;&line;

         args[0].equals("all")) {

        System.out.println("gc():");

        System.gc();

      }

      if(args[0].equals("finalize") &line;&line;

         args[0].equals("all")) {

        System.out.println("runFinalization():");

        System.runFinalization();

      }

    }

    System.out.println("bye!");

  }

} ///:~为什么执行java Garbage gc以后,当所有对象创建完(比如8000个),这时只清除了2000个(不定),应该只能创建47个对象啊

分析:

首先,在一个循环当中创建对象,并且只是创建,而不引用,也就是说这个对象会自动的被系统当作垃圾处理掉。但请注意,finalize()方法并不是立刻就会执行的,执行的时间完全由系统来决定。所以很有可能的情况是已经创建了20000个对象,才开始其中的某一个对象的清除工作(这可能和时间或者系统内容的占用有关)。看finalize()方法中的一段代码:

    if (!gcrun) {

        gcrun = true;

        System.out.println(

            "\nBeginning to finalize after" + created + "Chairs have been created\nat ");

     }

就会出现这样的结果:

Beginning to finalize after 25038 Chairs have been created

这时对象的创建过程仍在继续(因为已经Finalize的对象还不满47个,Chair.f还是false)。所以Chair.created会继续增加。

直到有47个对象被清除了,Chair.f被置成true了,创建对象的循环才结束。看main方法中的一段代码:

    System.out.println(

        "\nAfter all chairs have been created:\n"

            + "total created ="

            + Chair.created

            + ",total finalized ="

            + Chair.finalized+"\n");

如上所说,Chair.created是不断增加的,而在这段代码执行之前,又会有N个对象被释放掉了,所以finalized也增加了。

结果可能是这样的:

total created =29096,total finalized =73

其实这一过程和使用的JVM有很大关系,执行结果可能会很不相同。但有一点是可以肯定的,那就是我们无法确定JVM什么时候做对象的清除工作(这也是Thinking in java中这段代码的想要说明的),可能会在这个对象刚刚无用的时候就清除掉了,也可能滞后几秒,甚至永远不清除。

结论:

不能指望finalize()方法能稳定的工作,尤其不能依靠它来做文件的关闭等操作,由于finalize()的不确定性,往往得不到你想要的结果。事实上我们只需要知道所有无用的对象,JVM会自己清除就够了。省点心思去睡觉岂不是更好的一件事情 :)

posted @ 2005-11-01 13:05 FinalFantasy 阅读(736) | 评论 (2)编辑 收藏

2005年10月6日 #

 

洛阳的天气可真是讨厌,昨天好不容易放晴了一天,今天就又下起了大雨,本来计划好去买衣服的,现在只能泡汤了。这几天来上网查了很多的资料,为了组建一个PHP、JSP、ASP的全能平台,PHP跟JSP的平台是组建好了,可是ASP怎么样都不行,好不容易下了个IASP装上了,配置了之后却老是出现错误。哎NB怎么就不配个专业版的系统给我呢,这样我就不用那么费劲了,只要把IIS跟Apache整合起来就行了。趁着有点时间就把用apache组建的PHP、JSP平台教程整理出来了,说实话光这两个都费了我好多的劲呀,特别是JSP,网上的教程都不知道是什么年代写的了,几乎都不能用了,我废了好几天的功夫才把这些零件给找齐,所以还特别记下了下载的地址,要下的就要赶快了!好了,废话不多说了,往下看吧。对了,另外再多说一句,下面的配置是我安装我本机的安装地址的,如果你的安装地址跟我的不符,那么你就要一些相应的改进!还有,如果一下的下载地址无效了,你可以在我这留下你的邮箱,我可以将这些东西发给你。


前期准备: 

所需软件列表
1、apache_2.0.54-win32-x86-no_ssl.exe (Apache web服务器) http://apache.justdn.org/......2.0.54-win32-x86-no_ssl.exe
2、php-5.0.5-Win32 (PHP语言解析器)
4、jdk1.4.2(JAVA 语言环境)
5、jakarta-tomcat-5.5.12 (Tomcat JSP解析服务器) http://mirror.vmmatrix.ne......in/apache-tomcat-5.5.12.exe
7、mod_jk-1.2.14-apache-2.0.54.so.asc (整合Apache+Tomcat的plus) http://apache.linuxforum.......1.2.14-apache-2.0.54.so.asc(为了找这个文件都把我给找疯了,网上的教程到处都说要mod_jk_1.2.5_2.0.47.dll,可是我找了两天死都找不到,后来到apache的官方网站看着生硬的EN去查才找到这么个文件,看文件名直觉就告诉我找对了,现在的apache不都是用so扩展了么,而且在那个页面也说明了这一点,要使用还要改名,所以在这里特别指出下载地址,让大家少走很多的弯路)

开始安装:
一、 Apahce+PHP安装配置 

1、安装apache_2.0.54-win32-x86-no_ssl.exe,为了方便把路径改为c:\吧,其他都不用管一路next下去。
2、安装完成之后,apache服务自动加载,这时打开浏览器,浏览:http://localhost,出现apache欢迎页面(这步需要将C:\apache2\htdocs目录中的文件“index.html.en”改为“index.html”,方能显示);如果这步出现异常,请检查安装源文件,重新安装。
3. 安装php-5.0.5-Win32,一般下载的PHP文件为一个免安装的压缩包,解压到C:\PHP就可以。 
4. 配置PHP和Apache,使之能解析php程序。 
PHP配置:将C:\PHP\目录中的“php.ini-dist”改名“php.ini”,然后添加环境变量。在环境变量里的classpath中添加“.;c:\php;”,在新建一个“PHPRC”的变量,里面同样是添加“.;c:\php;” 
Apache配置: 
打开C:\apache2\conf\httpd.conf 

httpd.conf是apache的配置文件,在此配置文件最后添加以下语句,用以支持php程序: 

ScriptAlias /php/ "C:/PHP/" 

AddType application/x-httpd-php .php3 

AddType application/x-httpd-php .php 

AddType application/x-httpd-php .phtml 

Action application/x-httpd-php "/php/php.exe" 

ok,接下来重启Apache服务器(如果加载PHP成功,可以在Apache监控器中看到Apache/2.0.52(win32) PHP/5.0.4)就可以测试了PHP了,用编辑器编写如下语句: 
<?
phpinfo(); 

?> 

保存文件名为“test.php”到C:\apache2\htdocs目录,然后打开浏览器,浏览:http://localhost/test.php,出现PHP基本信息就说明配置成功。严格按以上说明安装配置,都会一次成功。

二、安装JDK和Tomcat

1. 安装j2sdk-1_4_2-windows-i586,JDK一定要在Tomcat之前安装,默认安装路径就可以。
2. 安装Jakarta-Tomcat-5.5.12,默认安装路径就可以。
4.设置环境变量(桌面->我的电脑->右键点击->选择“属性”->高级->环境变量),所有设置均在系统变量栏进行。
新建->变量名:JAVA_HOME
->变量值:C:\j2sdk1.4.2
新建->变量名:TOMCAT_HOME
->变量值:C:\Program Files\Apache Software Foundation\Tomcat 5.5
新建->变量名: PATH
->变量值:.;C:\j2sdk1.4.2\bin; (前面的“.;”一定要有)
修改增加环境变量 CLASSPATH (如果没有此变量名,则新建)
->增加变量值:.;C:\j2sdk1.4.2\lib\dt.jar;C:\j2sdk1.4.2\lib\tool.jar;
C:\j2sdk1.4.2\lib\NetComponents.jar;
C:\Program Files\Apache Software Foundation\Tomcat 5.5\common\classes;
C:\Program Files\Apache Software Foundation\Tomcat 5.5\common\lib;
C:\Program Files\Apache Software Foundation\Tomcat 5.5\common\lib\servlet-api.jar;(前面的“.;”一定要有)

5. 启动Tomcat服务器,打开浏览器,浏览:http://localhost:8080/ ,出现Tomcat欢迎页面;如果这步出现异常,请检查安装源文件,重新安装。

三、整合Apache+Tomcat服务器

1. 复制mod_jk-1.2.14-apache-2.0.54.so.asc文件到C:\Apache2\modules目录,并将其文件名改为mod_jk.so。
2. Apache配置:
C:\apahce2\conf\httpd.conf
httpd.conf
在此配置文件最后添加以下语句,用以支持jsp程序:
LoadModule jk_module modules/mod_jk.so

JkWorkersFile "C:/Program Files/Apache Software Foundation/Tomcat 5.5/conf/workers.properties"
JkMount /servlet/* ajp13
JkMount /*.jsp ajp13

还有要在
DirectoryIndex index.html index.html.var的后面加上default.jsp index.jsp(前面忘了说了,支持PHP还要加上index.php default.php)

3. 在C:\Program Files\Apache Software Foundation\Tomcat 5.5\conf\目录下,新建文件名为“workers.properties”的文件,将如下内容复制到新建文件workers.properties中。

workers.properties
# 只复制以下内容即可:

workers.tomcat_home=C:\Program Files\Apache Software Foundation\Tomcat 5.5
workers.java_home=C:\j2sdk1.4.2
ps=\
# worker.list=ajp13
worker.list=ajp12,ajp13

worker.ajp12.port=8007
worker.ajp12.host=localhost
worker.ajp12.type=ajp12
worker.ajp12.lbfactor=1

worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.lbfactor=1

worker.loadbalancer.type=lb

worker.loadbalancer.balanced_workers=ajp12, ajp13
worker.inprocess.type=jni
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)classes
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)jaxp.jar

worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)parser.jar

worker.inprocess.class_path=$(workers.tomcat_home)$(ps)common$(ps)lib$(ps)jasper.jar

worker.inprocess.class_path=$(workers.tomcat_home)$(ps)common$(ps)lib$(ps)servlet.jar

worker.inprocess.class_path=$(workers.tomcat_home)$(ps)common$(ps)lib$(ps)webserver.jar

worker.inprocess.class_path=$(workers.java_home)$(ps)lib$(ps)tools.jar

worker.inprocess.cmd_line=-config

worker.inprocess.cmd_line=$(workers.tomcat_home)/conf/jni_server.xml

worker.inprocess.cmd_line=-home

worker.inprocess.cmd_line=$(workers.tomcat_home)

worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)jvm.dll


worker.inprocess.stdout=$(workers.tomcat_home)$(ps)inprocess.stdout

worker.inprocess.stderr=$(workers.tomcat_home)$(ps)inprocess.stderr

worker.inprocess.sysprops=tomcat.home=$(workers.tomcat_home)

接下来重启Tomcat和Apache服务器(必须先重启Tomcat再重启Apache,不然会出错,如果加载JK成功,这个时候你可以在Apache监控器中看到Apache/2.0.52(win32) PHP/5.0.4 mod_jk/1.2.8)就可以测试了,把Tomcat的webapps这个目录拷贝到Apache的htdocs目录下面,然后直接在浏览器地址栏输入:http://localhost/webappshttp://localhost:8080如果显示的页面一样就说明成功了。

剩下的就是连接MySQL了,但是本人不才一个叫mm.mysql-2.0.4-bin.jar的文件怎么也找不到,只找到了个mysql-connector-java-3.1.5-gamma-bin.jar的文件,可是我试过了一点用都没有,所以连接数据库的教程等我试验成功再说拉!如果哪位高人能救救我的告诉我mm.mysql-2.0.4-bin.jar的下载地址或者告诉我IASP到底改如何配置,我真是感激不尽。


posted @ 2005-10-06 19:28 FinalFantasy 阅读(4131) | 评论 (6)编辑 收藏