??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲国产91在线,亚洲综合成人网在线观看,国产亚洲综合精品一区二区三区http://www.tkk7.com/gen-sky/category/40682.html勤思、}a、慎行、厚U、薄?/description>zh-cnThu, 28 Feb 2013 16:38:01 GMTThu, 28 Feb 2013 16:38:01 GMT60spring3 email 发送代?http://www.tkk7.com/gen-sky/articles/spring3_email.html星期?/dc:creator>星期?/author>Thu, 28 Feb 2013 10:08:00 GMThttp://www.tkk7.com/gen-sky/articles/spring3_email.htmlhttp://www.tkk7.com/gen-sky/comments/395869.htmlhttp://www.tkk7.com/gen-sky/articles/spring3_email.html#Feedback0http://www.tkk7.com/gen-sky/comments/commentRss/395869.htmlhttp://www.tkk7.com/gen-sky/services/trackbacks/395869.html配置代码都超q了M?nbsp;
不过配置代码都是常用的,留着备䆾吧?br />mavne pox 配置



 1 <dependency>
 2             <groupId>javax.mail</groupId>
 3             <artifactId>mail</artifactId>
 4             <version>1.4</version>
 5         </dependency>
 6     <dependency>
 7             <groupId>org.springframework</groupId>
 8             <artifactId>spring-beans</artifactId>
 9             <version>${org.springframework.version}</version>
10         </dependency>

spring-xml 配置
<bean id="propertyConfigurer"
        class
="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:cfg/config.properties</value>
            </list>
        </property>
    </bean>

    <bean id="mail"
        class
="org.springframework.mail.javamail.JavaMailSenderImpl">
        <!-- SMTP发送邮件的服务器的IP和端?nbsp;-->
        <property name="host" value="${mail.host}" />
        <property name="port" value="${mail.port}" />

        <!-- 登陆SMTP邮g发送服务器的用户名和密?nbsp;-->
        <property name="username" value="${mail.username}" />
        <property name="password" value="${mail.password}" />

        <!-- 获得邮g会话属?验证d邮g服务器是否成?/span>-->
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtp.auth">true</prop>
                <prop key="prop">true</prop>
                <prop key="mail.smtp.timeout">25000</prop>
            </props>
        </property>
    </bean>


properties 文g配置

mail.host=smtp.yeah.net
mail.port=25
mail.username=****
mail.password=****
java cd别ؓQ?br />
import org.springframework.context.support.AbstractApplicationContext;

import com.ms.AppContext;

public class SpringHelper {

    /**
     * 获取spring依赖注入的对?br />     * 
     * 
@param name
     * 
@return Object Bean
     
*/
    public static Object getBean(String name) {
        AbstractApplicationContext ctx = AppContext.getInstance()
                .getAppContext();

        return ctx.getBean(name);
    }
}


import java.util.ArrayList;
import java.util.List;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppContext {
    private static AppContext instance;

    private volatile AbstractApplicationContext appContext;

    public synchronized static AppContext getInstance() {
        if (instance == null) {
            instance = new AppContext();
        }

        return instance;
    }

    private AppContext() {
        List<String> list = new ArrayList<String>();
        list.add("/cfg/*.xml");

        String ss[] = list.toArray(new String[] {});
        for (int i = 0; i < ss.length; i++) {
            System.out.println("ss[" + i + "]" + ss[i]);

        }

        this.appContext = new ClassPathXmlApplicationContext(ss);
    }

    public AbstractApplicationContext getAppContext() {
        return appContext;
    }
}



import java.io.File;
import java.util.Date;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import com.ms.SpringHelper;
import com.util.Configuration;

/**
 * 发送邮?nbsp;工具
 * 
 * 
@author 
 * @file com.ms.util --- SentMaileUtil.java
 * 
@version 2013-2-28 -下午03:42:03
 
*/
public class SendMaileUtil {
    private static JavaMailSender javaMailSender;

    private static Logger logger = Logger.getLogger(SendMaileUtil.class);

    private static JavaMailSender newIntstance() {
        if (javaMailSender == null) {
            javaMailSender = (JavaMailSender) SpringHelper.getBean("mail");
        }
        return javaMailSender;
    }

    /**
     * 发送的文本试邮g
     * 
     * 
@param to
     * 
@param mailSubject
     * 
@param mailBody
     
*/
    public static void sendTextMaile(String to, String mailSubject,
            String mailBody) {
        if (logger.isDebugEnabled())
            logger.debug("准备发送文本Ş式的邮g");
        SimpleMailMessage mail1 = new SimpleMailMessage();
        String from = Configuration.getValue("mail.form");
        mail1.setFrom(from);// 发送h名片
        mail1.setTo(to);// 收g人邮?/span>
        mail1.setSubject(mailSubject);// 邮g主题
        mail1.setSentDate(new Date());// 邮g发送时?/span>
        mail1.setText(mailBody);

        // 发
        SimpleMailMessage[] mailMessages = { mail1 };
        newIntstance().send(mailMessages);

        if (logger.isDebugEnabled())
            logger.debug("文本形式的邮件发送成功!Q!");
    }

    /**
     * ?nbsp;HTML脚本形式邮g发?br />     * 
     * 
@param to
     * 
@param mailSubject
     * 
@param mailBody
     
*/
    public static void sendHtmlMail(String to, String mailSubject,
            String mailBody) {
        JavaMailSender mailSender = newIntstance();
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        try {
            if (logger.isDebugEnabled())
                logger.debug("HTML脚本形式邮g正在发?img src="http://www.tkk7.com/Images/dot.gif" alt="" />");
            // 讄utf-8或GBK~码Q否则邮件会有ؕ?/span>
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true,
                    "UTF-8");
            // 讄发送h名片
            String from = Configuration.getValue("mail.form");
            helper.setFrom(from);
            // 讄收g人名片和地址
            helper.setTo(new InternetAddress("\""
                    + MimeUtility.encodeText("gamil邮箱") + "\" <" + to + ">"));// 发送?br />            // 邮g发送时?/span>
            helper.setSentDate(new Date());
            // 讄回复地址
            helper.setReplyTo(new InternetAddress(from));
            // 讄抄送的名片和地址
            
// helper.setCc(InternetAddress.parse(MimeUtility.encodeText("抄送h001")
            
// + " <@163.com>," + MimeUtility.encodeText("抄送h002")
            
// + " <@foxmail.com>"));
            
// 主题
            helper.setSubject("ݞ피언쉽");
            // 邮g内容Q注意加参数trueQ表C启用html格式
            helper
                    .setText(
                            "<html><head></head><body><h1>hello!!我是乔布?lt;/h1></body></html>",
                            true);
            // 发?/span>
            mailSender.send(mimeMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (logger.isDebugEnabled())
            logger.debug("HTML脚本形式邮g发送成功!Q!");
    }

    /**
     * 以附件的形式发送邮?br />     * 
     * 
@param to
     *            收g人eamil 地址
     * 
@param toName
     *            收g人昵U?br />     * 
@param mailSubject
     *            主题
     * 
@param mailBody
     *            内容?br />     * 
@param files
     *            附g
     
*/
    public static void sendFileMail(String to, String toName,
            String mailSubject, String mailBody, File[] files) {
        JavaMailSender mailSender = newIntstance();
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        try {
            if (logger.isDebugEnabled())
                logger.debug("带附件和囄的邮件正在发?img src="http://www.tkk7.com/Images/dot.gif" alt="" />");

            // 讄utf-8或GBK~码Q否则邮件会有ؕ?/span>
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true,
                    "UTF-8");
            // 讄发送h名片
            String from = Configuration.getValue("mail.form");
            helper.setFrom(from);

            // 讄收g人邮?/span>
            helper.setTo(new InternetAddress("\""
                    + MimeUtility.encodeText(toName) + "\" <" + to + ">"));

            // 讄回复地址
            
// helper.setReplyTo(new InternetAddress("@qq.com"));

            
// 讄收g人抄送的名片和地址(相当于群发了)
            
// helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001")
            
// + " <@163.com>," + MimeUtility.encodeText("邮箱002")
            
// + " <@foxmail.com>"));

            
// 主题
            helper.setSubject(mailSubject);
            // 邮g内容Q注意加参数trueQ表C启用html格式
            helper.setText(mailBody);
            if (files != null && files.length > 0) {
                for (int i = 0; i < files.length; i++)
                    // 加入附g
                    helper.addAttachment(MimeUtility.encodeText(files[i]
                            .getName()), files[i]);
            }
            // 加入插图
            helper.addInline(MimeUtility.encodeText("pic01"), new File(
                    "c:/temp/2dd24be463.jpg"));
            // 发?/span>
            mailSender.send(mimeMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (logger.isDebugEnabled()) {
            logger.debug("带附件和囄的邮件发送成功!Q!");
        }
    }

    public static void main(String[] args) {
        PropertyConfigurator.configure(ClassLoader
                .getSystemResource("cfg/log4j.properties"));

        SendMaileUtil.sendTextMaile("*****@gmail.com",
                "Spring Mail 试邮g", "Hello,Boy,This is my Spring Mail,哈哈Q!");

        SendMaileUtil.sendHtmlMail("*****@gmail.com", nullnull);
        File file = new File("c:/temp");
        File[] fs = file.listFiles();

        SendMaileUtil.sendFileMail("******@yeah.net", "늧", "主题", "内容",
                fs);

    }
}









import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import com.pub.Forward;

/**
 * dproperties文g
 * 
@author 
 *
 
*/
public class Configuration
{
    private static Properties propertie;
    private InputStream in;
    private static Configuration config = new Configuration();
    
    /**
     * 初始化Configurationc?br />     
*/
    public Configuration()
    {
        propertie = new Properties();
        try {
//            System.out.println(System.getProperty("user.dir"));
//            inputFile = new FileInputStream("cfg/config.properties");
            in =  ClassLoader.getSystemResourceAsStream("cfg/config.properties");
            propertie.load(in);
            in.close();
        } catch (FileNotFoundException ex) {
            System.out.println("d属性文?-->p|Q? 原因Q文件\径错误或者文件不存在");
            ex.printStackTrace();
        } catch (IOException ex) {
            System.out.println("装蝲文g--->p|!");
            ex.printStackTrace();
        }        
    }
    

    
    /**
     * 重蝲函数Q得到key的?br />     * 
@param key 取得其值的?br />     * @return key的?br />     */
    public static  String getValue(String key)
    {
        if(propertie.containsKey(key)){
            String value = propertie.getProperty(key);//得到某一属性的?/span>
            return value;
        }
        else 
            return "";
    }//end getValue()

    


    
    public static void main(String[] args)
    {

        System.out.println(Configuration.getValue("aaa"));
        System.out.println(System.getProperty("user.dir"));


        
    }//end main()
    
}//end class ReadConfigInfo





























]]>
【找错题?出除list集合中的数字http://www.tkk7.com/gen-sky/articles/list.html星期?/dc:creator>星期?/author>Thu, 17 Jun 2010 07:36:00 GMThttp://www.tkk7.com/gen-sky/articles/list.htmlhttp://www.tkk7.com/gen-sky/comments/323722.htmlhttp://www.tkk7.com/gen-sky/articles/list.html#Feedback0http://www.tkk7.com/gen-sky/comments/commentRss/323722.htmlhttp://www.tkk7.com/gen-sky/services/trackbacks/323722.html 1     public static void main(String[] args) {
 2         List<String> list = new ArrayList<String>();
 3         list.add("a");
 4         list.add("b");
 5         list.add("c");
 6         list.add("136");
 7         list.add("14");
 8         list.add("f");
 9         
10         for(int i = 0;i<list.size();i++){
11             String str = list.get(i);
12             if(isNumeric(str)){
13                 list.remove(i);
14             }
15         }
16         for(int i = 0;i<list.size();i++){
17             System.out.println(list.get(i));
18         }
19     }
20     public static boolean isNumeric(String str) { // 判断字符串是否ؓ数字
21         Pattern pattern = Pattern.compile("[0-9]*");
22         Matcher isNum = pattern.matcher(str);
23         if (!isNum.matches()) {
24             return false;
25         }
26         return true;
27     }

]]>
[转] 垃圾攉史(Garbage Collection )http://www.tkk7.com/gen-sky/articles/GarbageCollection.html星期?/dc:creator>星期?/author>Thu, 03 Dec 2009 06:56:00 GMThttp://www.tkk7.com/gen-sky/articles/GarbageCollection.htmlhttp://www.tkk7.com/gen-sky/comments/304621.htmlhttp://www.tkk7.com/gen-sky/articles/GarbageCollection.html#Feedback0http://www.tkk7.com/gen-sky/comments/commentRss/304621.htmlhttp://www.tkk7.com/gen-sky/services/trackbacks/304621.html

垃圾攉史

本文发表?004q?月《CSDN开发高手?/p>

写作本文的初h惛_大家分n垃圾攉Q?Garbage Collection Q技术简单而有的发展双Ӏ动W之前,我站在窗边,望了望正在小区里装运垃圾的清zR。和生活中环卫工Z清运垃圾的工作相|软g开发里的垃圾收集其? 是一U自动打扫和清除内存垃圾的技术,它可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽Q这和生zd圑֠塞排污管道的 危险q没有什么本质的不同Q,以及不恰当的内存释放所造成的内存非法引用(q类g我们在生zM买到了一瓶已l过期三q的牛奶Q?

据历史学家们介绍Q四千多q前的古埃及人已l在城市里徏设了完善的排污和垃圾清运设施Q一千多q前的中国h更是修筑了当时世界上保洁能力最强的都市 ——长安。今天,当我们在软g开发中体验自动垃圾攉的便捷与舒适时Q我们至应当知道,q种拒绝杂ؕ、追求整z的“垃圾攉”_其实是hc自古以来就 已经具备了的?

拓荒时代

国内的程序员大多是在 Java 语言中第一ơ感受到垃圾攉技术的巨大力的,许多Z因此?Java 和垃圾收集看成了密不可分的整体。但事实上,垃圾攉技术早?Java 语言问世?30 多年已l发展和成熟h了, Java 语言所做的不过是把q项奇的技术带Cq大E序员n边而已?

如果一定要为垃圾收集技术找一个孪生兄弟,那么Q?Lisp 语言才是当之无愧的h选?1960 q前后诞生于 MIT ?Lisp 语言是第一U高度依赖于动态内存分配技术的语言Q?Lisp 中几乎所有数据都?#8220;?#8221;的Ş式出玎ͼ?#8220;?#8221;所占用的空间则是在堆中动态分配得到的? Lisp 语言先天具有的动态内存管理特性要?Lisp 语言的设计者必解军_中每一个内存块的自动释N题(否则Q?Lisp E序员就必然被程序中不计其数?free ?delete 语句Ҏ(gu)Q,q直接导致了垃圾攉技术的诞生和发展——说句题外话Q上大学Ӟ一位老师曑֑诉我们, Lisp 是对C软g开发技术A(ch)献最大的语言。我当时对这一说法不以为然Q布满了圆括P看上dq宫一L Lisp 语言怎么能比 C 语言? Pascal 语言更伟大呢Q不q现在,当我知道垃圾攉技术、数据结构技术、h工智能技术、ƈ行处理技术、虚拟机技术、元数据技术以及程序员们耳熟能详的许多技术都? 源于 Lisp 语言Ӟ我特别想向那位老师当面道歉Qƈ收回我当时的q稚x?

知道?Lisp 语言与垃圾收集的密切关系Q我们就不难理解Qؓ什么垃圾收集技术的两位先驱?J. McCarthy ?M. L. Minsky 同时也是 Lisp 语言发展史上的重要h物了?J. McCarthy ?Lisp 之父Q他在发?Lisp 语言的同时也W一ơ完整地描述了垃圾收集的法和实现方式; M. L. Minsky 则在发展 Lisp 语言的过E中成ؓ了今天好几种L垃圾攉法的奠Zh——和当时不少技术大师的l历怼Q?J. McCarthy ?M. L. Minsky 在许多不同的技术领域里都取得了令h艳M的成。也许,?1960 q代那个软g开发史上的拓荒时代里,思维敏捷、意志坚定的研究者更Ҏ(gu)成ؓ无所不能的西部硬汉吧?

在了解垃圾收集算法的h之前Q有必要先回一下内存分配的主要方式。我们知道,大多C的语言或运行环境都支持三种最基本的内存分配方式,它们分别是:

一、静态分配( Static Allocation Q:静态变量和全局变量的分配Ş式。我们可以把静态分配的内存看成是家里的耐用家具。通常Q它们无需释放和回Ӟ因ؓ没h会天天把大衣柜当作垃圾扔到窗外?

二、自动分配( Automatic Allocation Q:在栈中ؓ局部变量分配内存的Ҏ(gu)。栈中的内存可以随着代码块退出时的出栈操作被自动释放。这cM于到家中串门的访客,天色一晚就要各回各Ӟ除了个别 不识时务者以外,我们一般没必要把客人捆在垃圾袋里扫地出门?

三、动态分配( Dynamic Allocation Q:在堆中动态分配内存空间以存储数据的方式。堆中的内存块好像我们日怋用的巾U,用过了就得扔到垃圄里,否则屋内׃满地D。像我这L懒h? 梦都x一台家用机器h跟在w边打扫卫生。在软g开发中Q如果你懒得释放内存Q那么你也需要一台类似的机器人——这其实是一个由特定法实现的垃圾收? 器?

也就是说Q下面提到的所有垃圾收集算法都是在E序q行q程中收集ƈ清理废旧“巾U?#8221;的算法,它们的操作对象既不是静态变量,也不是局部变量,而是堆中所有已分配内存块?

引用计数Q?Reference Counting Q算?/h3>

1960 q以前,Z胎中?Lisp 语言设计垃圾攉机制ӞW一个想到的法是引用计数算法。拿巾U的例子来说Q这U算法的原理大致可以描述为:

午餐ӞZ把脑子里H然跛_来的设计灉|C来,我从巾U袋中抽Z张餐巄Q打在上面dpȝ架构的蓝图。按?#8220;巾U怋用规U之引用计数 ?#8221;的要求,d之前Q我必须先在巾U的一角写上计数?1 Q以表示我在使用q张巾U。这Ӟ如果你也想看看我ȝ蓝图Q那你就要把巾U怸的计数值加 1 Q将它改?2 Q这表明目前?2 个h在同时用这张餐巄Q当Ӟ我是不会允许你用q张巾U来擦E涕的Q。你看完后,必须把计数值减 1 Q表明你对该巾U的使用已经l束。同P当我餐巄上的内容全部誊写到笔记本上之后,我也会自觉地把餐巄上的计数值减 1 。此Ӟ不出意外的话Q这张餐巄上的计数值应当是 0 Q它会被垃圾攉器——假N是一个专门负责打扫卫生的机器人——捡h扔到垃圾里Q因为垃圾收集器的惟一使命是扑ֈ所有计数gؓ 0 的餐巄q清理它们?

引用计数法的优点和~陷同样明显。这一法在执行垃圾收集Q务时速度较快Q但法对程序中每一ơ内存分配和指针操作提出了额外的要求Q增加或减少 内存块的引用计数Q。更重要的是Q引用计数算法无法正释攑@环引用的内存块,Ҏ(gu)Q?D. Hillis 有一D风而精辟的Q?

一天,一个学生走?Moon 面前_“我知道如何设计一个更好的垃圾攉器了。我们必记录指向每个结点的指针数目?#8221; Moon 耐心地给q位学生讲了下面q个故事Q?#8220;一天,一个学生走?Moon 面前_‘我知道如何设计一个更好的垃圾攉器了……’”

D. Hillis 的故事和我们时候常说的“从前有山,׃有个庙,庙里有个老和?#8221;的故事有异曲同工之妙。这说明Q单是用引用计数算法还不以解军_圾收集中的所? 问题。正因ؓ如此Q引用计数算法也常常被研I者们排除在狭义的垃圾攉法之外。当Ӟ作ؓ一U最单、最直观的解x案,引用计数法本nh其不可替 代的优越性?1980 q代前后Q?D. P. Friedman Q?D. S. Wise Q?H. G. Baker {h对引用计数算法进行了数次改进Q这些改q得引用计数算法及其变U(如gq计数算法等Q在单的环境下,或是在一些综合了多种法的现代垃圾收集系l? 中仍然可以一展n手?

标记Q清除( Mark-Sweep Q算?/h3>

W一U实用和完善的垃圾收集算法是 J. McCarthy {h?1960 q提出ƈ成功地应用于 Lisp 语言的标讎ͼ清除法。仍以餐巄ZQ标讎ͼ清除法的执行过E是q样的:

午餐q程中,厅里的所有h都根据自q需要取用餐巄。当垃圾攉机器人想攉废旧巾U的时候,它会让所有用的人先停下来,然后Q依ơ询问餐 厅里的每一个hQ?#8220;你正在用巾U吗Q你用的是哪一张餐巄Q?#8221;机器人根据每个h的回{将Z正在使用的餐巄M记号。询问过E结束后Q机器h在餐厅里 L所有散落在桌上且没有记号的餐巄Q这些显焉是用q的废旧巾U)Q把它们l统扔到垃圾里?

正如其名U所暗示的那P标记Q清除算法的执行q程分ؓ“标记”?#8220;清除”两大阶段。这U分步执行的思\奠定了现代垃圾收集算法的思想基础。与引用 计数法不同的是Q标讎ͼ清除法不需要运行环境监每一ơ内存分配和指针操作Q而只要在“标记”阶段中跟t每一个指针变量的指向——用cM思\实现的垃 圾收集器也常被后人统UCؓ跟踪攉器( Tracing Collector Q?

伴随着 Lisp 语言的成功,标记Q清除算法也在大多数早期?Lisp q行环境中大攑ּ彩。尽最初版本的标记Q清除算法在今天看来q存在效率不高(标记和清除是两个相当耗时的过E){诸多缺P但在后面的讨ZQ我们可? 看到Q几乎所有现代垃圾收集算法都是标讎ͼ清除思想的gl,仅此一点, J. McCarthy {h在垃圾收集技术方面的贡献׃毫不亚于他们? Lisp 语言上的成就了?

复制Q?Copying Q算?/h3>

Z解决标记Q清除算法在垃圾攉效率斚w的缺P M. L. Minsky ?1963 q发表了著名的论?#8220;一U用双存储区的 Lisp 语言垃圾攉器( A LISP Garbage Collector Algorithm Using Serial Secondary Storage Q?#8221;?M. L. Minsky 在该论文中描q的法被h们称为复制算法,它也?M. L. Minsky 本h成功地引入到? Lisp 语言的一个实现版本中?

复制法别出心裁地将堆空间一分ؓ二,q用简单的复制操作来完成垃圾收集工作,q个思\相当有趣。借用巾U的比喻Q我们可以这L?M. L. Minsky 的复制算法:

厅被垃圾收集机器h分成南区和北Z个大完全相同的部分。午时Q所有h都先在南区用(因ؓI间有限Q用h数自然也减一半)Q用时? 以随意用餐巄。当垃圾攉机器为有必要回收废旧巾U时Q它会要求所有用者以最快的速度从南{Ud北区Q同旉w携带自己正在用的巾U? {所有h都{Ud北区之后Q垃圾收集机器h只要单地把南Z所有散落的巾U扔q垃圄q完成d了。下一ơ垃圾收集的工作q程也大致类|惟一的不 同只是h们的转移方向变成了从北区到南区。如此@环往复,每次垃圾攉都只需单地转移Q也是复制Q一ơ,垃圾攉速度无与伦比——当Ӟ对于用餐者往 q奔波于南北两区之间的辛劻I垃圾攉机器人是决不会流露出丝毫怜?zhn)的?

M. L. Minsky 的发明绝对算得上一U奇思妙惟뀂分区、复制的思\不仅大幅提高了垃圾收集的效率Q而且也将原本J纷复杂的内存分配算法变得前所未有地简明和DQ既然每? 内存回收都是Ҏ(gu)个半区的回收Q内存分配时也就不用考虑内存片{复杂情况,只要Ud堆顶指针Q按序分配内存可以了Q,q简直是个奇q!不过QQ何奇 q的出现都有一定的代h(hun)Q在垃圾攉技术中Q复制算法提高效率的代h(hun)是h为地可用内存羃?yu)了一半。实话实_q个代h(hun)未免也太高了一些?

无论优缺点如何,复制法在实践中都获得了可以与标讎ͼ清除法相比拟的成功。除?M. L. Minsky 本h?Lisp 语言中的工作以外Q从 1960 q代末到 1970 q代初, R. R. Fenichel ?J. C. Yochelson {h也相l在 Lisp 语言的不同实C对复制算法进行了改进Q?S. Arnborg 更是成功地将复制法应用C Simula 语言中?

xQ垃圾收集技术的三大传统法——引用计数算法、标讎ͼ清除法和复制算法——都已在 1960 q前后相l问世,三种法各有所长,也都存在致命的缺陗从 1960 q代后期开始,研究者的主要_֊逐渐转向对这三种传统法q行改进或整合,以扬镉K短,适应E序设计语言和运行环境对垃圾攉的效率和实时性所提出的更? 要求?

走向成熟

?1970 q代开始,随着U学研究和应用实늚不断深入Qh们逐渐意识刎ͼ一个理想的垃圾攉器不应在q行时导致应用程序的暂停Q不应额外占用大量的内存I间? CPU 资源Q而三U传l的垃圾攉法都无法满些要求。h们必L出更新的法或思\Q以解决实践中碰到的诸多N。当Ӟ研究者的努力目标包括Q?

W一Q提高垃圾收集的效率。用标讎ͼ清除法的垃圾收集器在工作时要消耗相当多?CPU 资源。早期的 Lisp q行环境攉内存垃圾的时间竟占到了系l总运行时间的 40% Q——垃圾收集效率的低下直接造就?Lisp 语言在执行速度斚w的坏名声Q直C天,许多条g反射似地误以为所?Lisp E序都奇慢无比?

W二Q减垃圾收集时的内存占用。这一问题主要出现在复制算法中。尽复制算法在效率上获得了质的H破Q但牺牲一半内存空间的代h(hun)仍然是巨大的。在计算机发展的早期Q在内存h?KB 计算的日子里Q浪费客L一半内存空间简直就是在变相敲诈或拦路打劫?

W三Q寻扑֮时的垃圾攉法。无论执行效率如何,三种传统的垃圾收集算法在执行垃圾攉d旉必须打断E序的当前工作。这U因垃圾攉而造成? 延时是许多程序,特别是执行关键Q务的E序没有办法容忍的。如何对传统法q行改进Q以便实CU在后台(zhn)?zhn)执行Q不影响——或臛_看上M影响——当? q程的实时垃圾收集器Q这昄是一件更h战性的工作?

研究者们探寻未知领域的决心和研究工作的进展速度同样令h惊奇Q在 1970 q代?1980 q代的短短十几年中,一大批在实用系l中表现优异的新法和新思\脱颖而出。正是因为有了这些日成熟的垃圾攉法Q今天的我们才能?Java ? .NET 提供的运行环境中随心所Ʋ地分配内存块,而不必担心空间释放时的风险?

标记Q整理( Mark-Compact Q算?/h3>

标记Q整理算法是标记Q清除算法和复制法的有机结合。把标记Q清除算法在内存占用上的优点和复制算法在执行效率上的牚wl合hQ这是所有h都希 望看到的l果。不q,两种垃圾攉法的整合ƈ不像 1 ?1 {于 2 那样单,我们必须引入一些全新的思\?1970 q前后, G. L. Steele Q?C. J. Cheney ?D. S. Wise {研I者陆l找C正确的方向,标记Q整理算法的轮廓也逐渐清晰了v来:

在我们熟(zhn)的厅里,q一ơ,垃圾攉机器Z再把厅分成两个南北区域了。需要执行垃圾收集Q务时Q机器h先执行标讎ͼ清除法的第一个步骤,? 所有用中的餐巄d标记Q然后,机器人命令所有就者带上有标记的餐巄向餐厅的南面集中Q同时把没有标记的废旧餐巄扔向厅北面。这样一来,机器 人只消站在餐厅北面,怀抱垃圄Q迎接扑面而来的废旧餐巄p了?

实验表明Q标讎ͼ整理法的M执行效率高于标记Q清除算法,又不像复制算法那样需要牺牲一半的存储I间Q这昄是一U非常理想的l果。在许多C的垃圾收集器中,Z都用了标记Q整理算法或其改q版本?

增量攉Q?Incremental Collecting Q算?/h3>

对实时垃圾收集算法的研究直接D了增量收集算法的诞生?

最初,Z关于实时垃圾攉的想法是q样的:Zq行实时的垃圾收集,可以设计一个多q程的运行环境,比如用一个进E执行垃圾收集工作,另一个进E执行程序代码。这样一来,垃圾攉工作看上d仿佛(jng)是在后台(zhn)?zhn)完成的,不会打断E序代码的运行?

在收集餐巄的例子中Q这一思\可以被理解ؓQ垃圾收集机器h在h们用的同时L废弃的餐巄q将它们扔到垃圾里。这个看似简单的思\会在设计 和实现时Cq程间冲H的N。比如说Q如果垃圾收集进E包括标记和清除两个工作阶段Q那么,垃圾攉器在W一阶段中辛辛苦苦标记出的结果很可能被另一? q程中的内存操作代码修改得面目全非,以至于第二阶D늚工作没有办法开展?

M. L. Minsky ?D. E. Knuth 对实时垃圾收集过E中的技术难点进行了早期的研IӞ G. L. Steele ? 1975 q发表了题ؓ“多进E整理的垃圾攉Q?Multiprocessing compactifying garbage collection Q?#8221;的论文,描述了一U被后hUCؓ“ Minsky-Knuth-Steele 法”的实时垃圾收集算法?E. W. Dijkstra Q?L. Lamport Q?R. R. Fenichel ?J. C. Yochelson {h也相l在此领域做Z各自的A(ch)献?1978 q_ H. G. Baker 发表?#8220;串行计算Z的实时表处理技术( List Processing in Real Time on a Serial Computer Q?#8221;一文,pȝ阐述了多q程环境下用于垃圾收集的增量攉法?

增量攉法的基仍是传统的标讎ͼ清除和复制算法。增量收集算法通过对进E间冲突的妥善处理,允许垃圾攉q程以分阶段的方式完成标记、清理或? 制工作。详l分析各U增量收集算法的内部机理是一件相当繁琐的事情Q在q里Q读者们需要了解的仅仅是: H. G. Baker {h的努力已l将实时垃圾攉的梦惛_成了现实Q我们再也不用ؓ垃圾攉打断E序的运行而烦g?

分代攉Q?Generational Collecting Q算?/h3>

和大多数软g开发技术一Pl计学原理总能在技术发展的q程中v到强力催化剂的作用?1980 q前后,善于在研I中使用l计分析知识的技术h员发玎ͼ大多数内存块的生存周期都比较短,垃圾攉器应当把更多的精力放在检查和清理新分配的内存块上。这 个发现对于垃圾收集技术的价值可以用巾U的例子概括如下Q?

如果垃圾攉机器够聪明,事先摸清了餐厅里每个人在用餐时用餐巄的习惯——比如有些h喜欢在用前后各用掉一张餐巄Q有的h喜欢自始至终 攥着一张餐巄不放Q有的h则每打一个喷嚏就用去一张餐巄——机器h可以制定出更完善的巾U回收计划,qL在h们刚扔掉巾U没多久把垃圾? 走。这U基于统计学原理的做法当然可以让厅的整z度成倍提高?

D. E. Knuth Q?T. Knight Q?G. Sussman ?R. Stallman {h对内存垃圄分类处理做了最早的研究?1983 q_ H. Lieberman ?C. Hewitt 发表了题?#8220;Z对象寿命的一U实时垃圾收集器Q?A real-time garbage collector based on the lifetimes of objects Q?#8221;的论文。这著名的论文标志着分代攉法的正式诞生。此后,?H. G. Baker Q?R. L. Hudson Q?J. E. B. Moss {h的共同努力下Q分代收集算法逐渐成ؓ了垃圾收集领域里的主技术?

分代攉法通常堆中的内存块按寿命分ؓ两类Q年老的和年ȝ。垃圾收集器使用不同的收集算法或攉{略Q分别处理这两类内存块,q特别地把主? 工作旉花在处理q轻的内存块上。分代收集算法垃圾攉器在有限的资源条件下Q可以更为有效地工作——这U效率上的提高在今天?Java 虚拟Z得到了最好的证明?

应用潮

Lisp 是垃圾收集技术的W一个受益者,但显然不是最后一个。在 Lisp 语言之后Q许许多多传l的、现代的、后C的语a已经把垃圾收集技术拉入了自己的怀抱。随便D几个例子吧:诞生?1964 q的 Simula 语言Q?1969 q的 Smalltalk 语言Q?1970 q的 Prolog 语言Q?1973 q的 ML 语言Q?1975 q的 Scheme 语言Q?1983 q的 Modula-3 语言Q?1986 q的 Eiffel 语言Q?1987 q的 Haskell 语言……它们都先后用了自动垃圾攉技术。当Ӟ每一U语a使用的垃圾收集算法可能不相同,大多数语a和运行环境甚臛_时用了多种垃圾攉法。但 无论怎样Q这些实例都说明Q垃圾收集技术从诞生的那一天v׃是一U曲高和寡的“学院z?#8221;技术?

对于我们熟?zhn)?C ?C++ 语言Q垃圾收集技术一样可以发挥巨大的功效。正如我们在学校中就已经知道的那P C ?C++ 语言本nq没有提供垃圾收集机Ӟ但这q不妨碍我们在程序中使用h垃圾攉功能的函数库或类库。例如,早在 1988 q_ H. J. Boehm ?A. J. Demers 成功地实现了一U用保守垃圾收集算法( Conservative GC Algorithmic Q的函数库(参见 http://www.hpl.hp.com/personal/Hans_Boehm/gc Q。我们可以在 C 语言?C++ 语言中用该函数库完成自动垃圾收集功能,必要Ӟ甚至q可以让传统?C/C++ 代码与用自动垃圾收集功能的 C/C++ 代码在一个程序里协同工作?

1995 q诞生的 Java 语言在一夜之间将垃圾攉技术变成了软g开发领域里最为流行的技术之一。从某种角度_我们很难分清I竟? Java 从垃圾收集中受益Q还是垃圾收集技术本w?Java 的普及而扬名。值得注意的是Q不同版本的 Java 虚拟Z用的垃圾攉机制q不完全相同Q?Java 虚拟机其实也l过了一个从单到复杂的发展过E。在 Java 虚拟机的 1.4.1 版中Qh们可以体验到的垃圾收集算法就包括分代攉、复制收集、增量收集、标讎ͼ整理、ƈ行复Ӟ Parallel Copying Q、ƈ行清除( Parallel Scavenging Q、ƈ发( Concurrent Q收集等许多U, Java E序q行速度的不断提升在很大E度上应该归功于垃圾攉技术的发展与完善?

管历史上已l有许多包含垃圾攉技术的应用q_和操作系l出玎ͼ?Microsoft .NET 却是W一U真正实用化的、包含了垃圾攉机制的通用语言q行环境。事实上Q?.NET q_上的所有语aQ包?C# ?Visual Basic .NET ?Visual C++ .NET ?J# {等Q都可以通过几乎完全相同的方式?.NET q_提供的垃圾收集机制。我们似乎可以断aQ?.NET 是垃圾收集技术在应用领域里的一ơ重大变革,它垃圾攉技术从一U单U的技术变成了应用环境乃至操作pȝ中的一U内在文化。这U变革对未来软g开发技? 的媄响力也许要远q超q?.NET q_本n的商业h(hun)倹{?

大势所?/h3>

今天Q致力于垃圾攉技术研I的Z仍在不懈努力Q他们的研究方向包括分布式系l的垃圾攉、复杂事务环境下的垃圾收集、数据库{特定系l的垃圾攉{等?

但在E序员中_仍有不少人对垃圾攉技术不屑一,他们宁愿怿自己逐行~写?free ?delete 命oQ也不愿把垃圾收集的重Q交给那些在他们看来既蠢又W的垃圾攉器?

我个为,垃圾攉技术的普及是大势所,q就像生zM来好一h庸置疑。今天的E序员也怼因ؓ垃圾攉器要占用一定的 CPU 资源而对其望而却步,但二十多q前的程序员q曾因ؓ高语言速度太慢而坚持用机器语言写程序呢Q在g速度日新月异的今天,我们是要吝惜那一点儿旉损? 而踟w不前,q是该坚定不Ud站在代码和运行环境的净化剂——垃圾收集的一边呢Q?

[王咏刚,2003q?2月]



]]>
垃圾回收工作机制 学习自《JavaE序? 上班那点事儿?/title><link>http://www.tkk7.com/gen-sky/articles/285795.html</link><dc:creator>星期?/dc:creator><author>星期?/author><pubDate>Tue, 07 Jul 2009 05:23:00 GMT</pubDate><guid>http://www.tkk7.com/gen-sky/articles/285795.html</guid><wfw:comment>http://www.tkk7.com/gen-sky/comments/285795.html</wfw:comment><comments>http://www.tkk7.com/gen-sky/articles/285795.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/gen-sky/comments/commentRss/285795.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/gen-sky/services/trackbacks/285795.html</trackback:ping><description><![CDATA[<p><strong>4.5 内存垃圾回收问题</strong></p> <p><strong>那本谭浩Z~的Java入门教材_</strong></p> <p><font face="楷体_GB2312">……</font></p> <p><font face="楷体_GB2312">1、简单?/font></p> <p><font face="楷体_GB2312">设计Java语言的出发点是Ҏ(gu)~程Q不需要深奥的知识。Java语言的风格十分接qC++语言Q但要比C++单得多。Java舍弃了一些不常用的、难以理解的、容易؜淆的成分Q如q算W重载、多l承{。增加了自动垃圾搜集功能Q用于回收不再用的内存区域。这不但使程序易于编写,而且大大减少了由于内存分配而引发的问题?/font></p> <p><font face="楷体_GB2312">……</font></p> <p>q样cM的描q出现在众多的Java入门U教材中Q非常容易让Z忽略了内存垃圑֛收的问题Q其实Java的垃圑֛攉q是需要关注一下的。这个问题在招聘单位的笔试题中出现的频率也比较高Q我们需要好好的研究一下Java的垃圑֛收机制?/p> <p><strong>4.5.1 什么是内存垃圾Q哪些内存符合垃圄标准</strong></p> <p>我们在前面讲q了Q堆是一?q行?数据区,是通过"new"{指令徏立的QJava的堆是由Java的垃圑֛收机制来负责处理的,堆是动态分配内存大,垃圾攉器可以自动回收不再用的内存I间?/p> <p>也就是说Q所谓的"内存垃圾"是指在堆上开辟的内存I间在不用的时候就变成?垃圾"?/p> <p>C++或其他程序设计语a中,必须q序员自行声明产生和回Ӟ否则其中的资源将消耗,造成资源的浪费甚x机。但手工回收内存往往是一复杂而艰巨的工作。因预先定占用的内存空间是否应该被回收是非常困隄Q如果一D늨序不能回收内存空_而且在程序运行时pȝ中又没有了可以分配的内存I间Ӟq段E序只能崩溃?/p> <p>Java和C++相比的优势在于,q部?垃圾"可以被Java 虚拟机(JVMQ中的一个程序发现ƈ自动清除掉,而不用程序员自己想着"delete"了?/p> <p>Java语言提供了一个系l的线E,卛_圾收集器U程QGarbage Collection ThreadQ,来跟t每一块分配出ȝ内存I间Q当JVM处于I闲循环Ӟ自动回收每一块可以回收的内存?/p> <p><strong>4.5.1.1 垃圾回收工作机制</strong></p> <p>垃圾攉器线E它是一U低优先U的U程Q它必须在一个JavaE序的运行过E中出现内存I闲的时候才去进行回收处理?/p> <p>垃圾攉器系l有其判断内存块是否需要回收的判断标准的。垃圾收集器完全是自动被执行的,它不能被强制执行Q即使程序员能明地判断出某一块内存应该被回收了,也不能强制执行垃圑֛收程序进行垃圑֛收?/p> <p>E序员可以做的只有调?System.gc()"?"执行垃圾攉器程序,但是q个垃圾攉E序什么时候被执行以及是否被执行了Q都是不不能控制的。但是虽然垃圾收集器是低优先U的U程Q却在系l内存可用量q低Ӟ它仍然可能会H发地执行来挽救pȝ?/p> <p><strong>4.5.1.2 哪些W合"垃圾"标准</strong></p> <p>如果想了解JVM的垃圑֛Ӟ必要知道JVM垃圾回收的标准?/p> <p>垃圾攉器的"垃圾"标准Q对象已l不能被E序中的其他E序所引用的时候,那么q个对象的内存空间已l没有用了?/p> <p>比如当一个方法执行完毕时Q在q个Ҏ(gu)中声明的对象p出其声明周期Q这时候就可以被当作垃圾收集了Q只有当q个Ҏ(gu)被再ơ被调用时才会被重新创徏?/p> <p>例如Q?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>……<br /> public void function(){<br /> OBJ obj=new OBJ();<br /> ……<br /> }<br /> ……<br /> </pre> </td> </tr> </tbody> </table> <p>另外q可以将对象的引用变量初始化为null|也可以来暗示垃圾攉器来攉该对象?/p> <p>例如Q?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>……<br /> OBJ obj=new OBJ();<br /> Obj=null;<br /> ……<br /> </pre> </td> </tr> </tbody> </table> <p> </p> <p><strong>finalize()在该对象垃圾回收前调?/strong></p> <p>垃圾攉器跟t每一个对象,把那些不可到辄对象占有的内存空间收集v来,q且在每ơ进行垃圾收集之前,垃圾攉器都会调用一下finalize()Ҏ(gu)。Java语言允许E序员给M对象dfinalize( )Ҏ(gu)Q但也不能过分依赖该Ҏ(gu)对系l资源的回收和再利用Q因个方法调用后的执行结果是不可预知的。对于Q何给定对象,Java 虚拟机最多只调用一? finalize Ҏ(gu)?</p> <p>我们用这个程序来演示一下:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class finalizeTest{<br /> public static void main( String[] args ){<br />  finalizeTest ft=new finalizeTest();<br />  ft.loading();<br />  byte bs[]=new byte[1450000];<br /> }<br /> public void loading(){<br />  test t=new test();<br />  t.callme();<br /> }<br /> }<br /> class test{<br /> protected void finalize(){<br /> System.out.println("call finalize");<br /> }<br /> public void callme(){<br /> System.out.println("callme");<br /> }<br /> }</pre> </td> </tr> </tbody> </table> 我们在命令行中键入如下命令:<br /> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>java -Xmx1k finalizeTest</pre> </td> </tr> </tbody> </table> E序q行l果如图 3 10所C?br />                                        <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/113425571.jpg" alt="" border="0" /><br /> <p>q时候,我们JVM所许可使用的最大内存设|成"1k"Q当内存被占满前JVM会首先去q行内存回收Q于是失L动的"test"对象被回Ӟ在回收前调用?finalize()"?br /> </p> <p><strong>4.5.2 JVM垃圾回收的相关知?/strong></p> <p>JVM使用的是分代垃圾回收的方式,主要是因为在E序q行的时候会有如下特点:</p> <p>大多数对象在创徏后很快就没有对象使用它了?/p> <p>大多数在一直被使用的对象很再d用新创徏的对象?/p> <p>因此将Java对象分ؓ"q轻"对象?q?对象QJVM内存堆QHeapQ分Z个区域,一个是"q轻"区,另一个是"?区,Java这两个区域分别UC?新生??老生??/p> <p>"新生?区域中,l大多数新创建的对象都存攑֜q个区域里,此区域一般来说较?yu)而且垃圾回收频率较高Q同时因?新生?采用的算法和其存攄对象的特点,使该区域垃圾回收的效率也非常高?/p> <p>?老生?区域中存攄是在"新生?中生存了较长旉的对象,q些对象被转移?老生?区。这个区域一般要大一些而且增长的速度相对?新生?要慢一些,"老生?垃圾回收的执行频率也会低很多?/p> <p>׃JVM在垃圑֛收处理时会消耗一定的pȝ资源Q因此有时候通过JVM启动的时候添加相兛_数来控制"新生?区域的大,来调整垃圑֛收处理的频率非常有用。以便于我们更合理的利用pȝ资源?/p> <p>"新生?区域讄参数?-Xmn"Q用q个参数可以制定"新生?区域的大?/p> <p>我们来D一个例子说明:</p> <p>我们qpȝ自带的程序作Z子,在命令行上键入如下指令:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>CD C:"java"demo"jfc"SwingSet2[回R]<br /> C:"java"demo"jfc"SwingSet2>java -jar -verbose:gc<br /> -Xmn4m XX:+PrintGCDetails SwingSet2.jar[回R]<br /> </pre> </td> </tr> </tbody> </table> 上面加入了一个新的参?XX:+PrintGCDetails"Q这个参数能够打印出GC的详l信息。屏q输出如下(节选)Q?br /> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>[GC [DefNew: 3469K->84K(3712K), 0.0007778 secs] <br /> 23035K->19679K(28728K), 0.0009191 secs]<br /> [GC [DefNew: 3284K->171K(3712K), 0.0007283 secs] <br /> 22878K->19766K(28728K), 0.0008669 secs]<br /> [GC [DefNew: 3476K->260K(3712K), 0.0008504 secs] <br /> 23071K->19855K(28728K), 0.0009862 secs]<br /> [GC [DefNew: 3502K->87K(3712K), 0.0009267 secs] <br /> 23096K->19682K(28728K), 0.0010610 secs]</pre> </td> </tr> </tbody> </table> <p>我们需要解释一下输出的详细内容的意思,拿第一行输出来_</p> <p>"DefNew: 3469K->84K(3712K), 0.0007778 secs"是指"新生?的垃圑֛收情况,q里的意思是从占?469K内存I间变ؓ84K内存I间Q用?.0007778U?/p> <p>"23035K->19679K(28728K), 0.0009191 secs"是指MGC的回收情况,整体堆空间占用从23035K降低?9679K的水qI用时0.0009191U?/p> <p>那么Q这时候我们在?新生?的内存设?MQƈ把堆的最大可控D定ؓ32MQ再L行,键入如下指oQ?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>java -jar -verbose:gc -Xmn8m -Xmx32m <br /> XX:+PrintGCDetails SwingSet2.jar[回R]</pre> </td> </tr> </tbody> </table> 得到的结果如下(节选)Q?br /> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>[GC [DefNew: 6633K->6633K(7424K), 0.0000684 secs]<br /> [Tenured: 18740K->18820K(24576K), 0.0636505 secs] <br /> 25374K->18820K(32000K), 0.0639274 secs]<br /> [GC [DefNew: 6646K->6646K(7424K), 0.0002581 secs]<br /> [Tenured: 18820K->18884K(24576K), 0.0651957 secs] <br /> 25467K->18884K(32000K), 0.0658804 secs]<br /> [GC [DefNew: 6611K->6611K(7424K), 0.0000668 secs]<br /> [Tenured: 18884K->18505K(24576K), 0.0931406 secs] </pre> <pre>25496K->18505K(32000K), 0.0934295 secs]</pre> </td> </tr> </tbody> </table> <p><font face="楷体_GB2312">q个l果说明Q?/font></p> <p><font face="楷体_GB2312">"[DefNew: 6633K->6633K(7424K), 0.0000684 secs]"是指"新生?的垃圑֛收情况,q里的意思是从占?633K内存I间变ؓ6633K内存I间Q用?. 0000684U?br /> "25374K->18820K(32000K), 0.0639274 secs"是指MGC的回收情况,整体堆空间占用从25374K降低?8820K的水qI用时0. 0639274U?br /> "[Tenured: 18740K->18820K(24576K), 0.0636505 secs]"是指"老生?GC的回收情况,整体堆空间占用从18740K降低?8820K的水qI用时0.0009012U?/font></p> <p>通过q些参数的调整我们可以看到在处理垃圾攉问题Ӟ从垃圑֛收的频率是时间方面的变化Q我们可以根据不同程序的不同情况予以调整?/p> <p>最后有必要提一下GC的相兛_敎ͼ</p> <p><font face="楷体_GB2312">-XX:+PrintGCDetails 昄GC的详l信?br /> -XX:+PrintGCApplicationConcurrentTime 打印应用执行的时?br /> -XX:+PrintGCApplicationStoppedTime 打印应用被暂停的旉<br /> 注:":"后的"+"可C开启此选项,如果?-"号那么表C关闭此选项?/font></p>  <br /> <img src ="http://www.tkk7.com/gen-sky/aggbug/285795.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/gen-sky/" target="_blank">星期?/a> 2009-07-07 13:23 <a href="http://www.tkk7.com/gen-sky/articles/285795.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存控制效率优化的启C? 学习自《Java E序? 上班那点事儿?/title><link>http://www.tkk7.com/gen-sky/articles/285791.html</link><dc:creator>星期?/dc:creator><author>星期?/author><pubDate>Tue, 07 Jul 2009 05:19:00 GMT</pubDate><guid>http://www.tkk7.com/gen-sky/articles/285791.html</guid><wfw:comment>http://www.tkk7.com/gen-sky/comments/285791.html</wfw:comment><comments>http://www.tkk7.com/gen-sky/articles/285791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/gen-sky/comments/commentRss/285791.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/gen-sky/services/trackbacks/285791.html</trackback:ping><description><![CDATA[启示一QString和StringBuffer的不同之?br /> <p>怿大家都知道String和StringBuffer之间是有区别的,但究竟它们之间到底区别在哪里Q我们就再本节中一探究竟,看看能给我们些什么启C。还是刚才那个程序,我们把它改一改,本E序中的Stringq行无限ơ的累加Q看看什么时候抛出内存超限的异常Q程序如下所C:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class MemoryTest{<br /> <br /> public static void main(String args[]){<br /> <br /> String s="abcdefghijklmnop";<br /> <br /> System.out.print("当前虚拟机最大可用内存ؓ:");<br /> <br /> System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+"M");<br /> <br /> System.out.print("循环前,虚拟机已占用内存:");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> int count = 0;<br /> <br /> while(true){<br /> <br /> try{<br /> <br /> s+=s;<br /> <br /> count++;<br /> <br /> }<br /> <br /> catch(Error o){<br /> <br /> System.out.println("循环ơ数:"+count);<br /> <br /> System.out.println("String实际字节?"+s.length()/1024/1024+"M");<br /> <br /> System.out.print("循环后,已占用内?");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> System.out.println("Catch到的错误:"+o);<br /> <br /> break;<br /> <br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> }</pre> </td> </tr> </tbody> </table> E序q行后,果然不一会儿的功夫就报出了异常,如图 3 3所C?<br />                              <img alt="" src="http://www.tkk7.com/images/blogjava_net/gen-sky/111125320.jpg" width="512" height="262" /> <br /> <p>我们注意刎ͼ在String的实际字节数只有8M的情况下Q@环后已占内存数竟然已l达C63.56M。这说明QStringq个对象的实际占用内存数量与其自w的字节C相符。于是,在@?9ơ的时候就已经?OutOfMemoryError"的错误了?/p> <p>因此Q应该少用Stringq东西,特别? String?+="操作Q不仅原来的String对象不能l箋使用Q而且又要产生多个新对象,因此会较高的占用内存?/p> <p>所以必要改用StringBuffer来实现相应目的,下面是改用StringBuffer来做一下测试:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class MemoryTest{<br /> <br /> public static void main(String args[]){<br /> <br /> StringBuffer s=new StringBuffer("abcdefghijklmnop");<br /> <br /> System.out.print("当前虚拟机最大可用内存ؓ:");<br /> <br /> System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+"M");<br /> <br /> System.out.print("循环前,虚拟机已占用内存:");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> int count = 0;<br /> <br /> while(true){<br /> <br /> try{<br /> <br /> s.append(s);<br /> <br /> count++;<br /> <br /> }<br /> <br /> catch(Error o){<br /> <br /> System.out.println("循环ơ数:"+count);<br /> <br /> System.out.println("String实际字节?"+s.length()/1024/1024+"M");<br /> <br /> System.out.println("循环后,已占用内?");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> System.out.println("Catch到的错误:"+o);<br /> <br /> break;<br /> <br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> }</pre> </td> </tr> </tbody> </table> 我们String改ؓStringBuffer以后Q在q行时得C如下l果Q如? 3 4所C?br />                             <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/111227471.jpg" alt="" border="0" /><br /> q次我们发现Q当StringBuffer所占用的实际字节数?16M"的时候才产生溢出Q整整比上一个程序的String实际字节?8M"多了一倍?br /> <p><strong>启示2Q用"-Xmx"参数来提高内存可控制?/strong></p> <p>前面我们介绍q?-Xmx"q个参数的用法,如果我们q是处理刚才的那个用StringBuffer的JavaE序Q我们用"-Xmx1024m"来启动它Q看看它的@环次数有什么变化?/p> <p>输入如下指oQ?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>java -mx1024m MemoryTest</pre> </td> </tr> </tbody> </table> 得到l果如图 3 5所C?br />                             <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/111628142.jpg" alt="" border="0" /><br /> <p>那么通过使用"-Xmx"参数其可控内存量扩大至1024M后,那么q个E序C1G的时候才内存限Q从而内存的可控性提高了?/p> <p>但扩大内存用量永远不是最l的解决Ҏ(gu)Q如果你的程序没有去更加的优化,早晚q是会超限的?/p> <p><strong>启示3Q二l数l比一l数l占用更多内存空?/strong></p> <p>对于内存占用的问题还有一个地方值得我们注意Q就是二l数l的内存占用问题?/p> <p>有时候我们一厢情愿的认ؓQ?/p> <p>二维数组的占用内存空间多无非是二维数组的实际数l元素数比一l数l多而已Q那么二l数l的所占空_一定是实际甌的元素数而已?/p> <p>但是Q事实上q不是这LQ对于一个二l数l而言Q它所占用的内存空间要q远大于它开辟的数组元素数。下面我们来看一个一l数l程序的例子Q?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class MemFor{<br /> <br /> public static void main (String[] args) {<br /> <br /> try{<br /> <br /> int len=1024*1024*2;   //讑֮循环ơ数<br /> <br /> byte [] abc=new byte[len];<br /> <br /> for (int i=0;i<len;i++){<br /> <br /> abc[i]=(byte)i;<br /> <br /> }<br /> <br /> System.out.print("已占用内?"); <br /> <br /> System.out.println(<br /> <br /> Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> }<br /> <br /> catch(Error e){<br /> <br /> }<br /> <br /> }<br /> <br /> }</pre> </td> </tr> </tbody> </table> q个E序是开辟了"1024*1024*2"?M的数l元素的一l数l,q行q个E序得到的结果如? 3 6所C,E序q行l果提示"已占用内存:3M"?br />                                        <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/111832715.jpg" alt="" border="0" /> <br /> <br /> <br /> <p>我们再将q个E序q行修改Q改Z个二l数l,q个二维数组的元素数量我们也量的和上一个一l数l的元素数量保持一致?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class MemFor{<br /> <br /> public static void main (String[] args) {<br /> <br /> try{<br /> <br /> int len=1024*1024;  //讑֮循环ơ数<br /> <br /> byte [][] abc=new byte[len][2];<br /> <br /> for (int i=0;i<len;i++){<br /> <br /> abc[i][0]=(byte)i;<br /> <br /> abc[i][1]=(byte)i;<br /> <br /> }<br /> <br /> System.out.print("已占用内?"); <br /> <br /> System.out.println(<br /> <br /> Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> }<br /> <br /> catch(Error e){<br /> <br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> </pre> </td> </tr> </tbody> </table> 当我们把甌的元素数量未变,只是二l数l的行数定ؓ"1024*1024"列数定ؓ"2"Q和刚才的那个一l数l?1024*1024*2"的数量完全一_但我们得到的q算l果如图 3 7所C,竟然占用辑ֈ?9M的空间?br />                                      <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/111922889.jpg" alt="" border="0" /><br /> 我们姑且不管造成q种情况的原因,我们只要知道一点就够了Q那是"二维数组占内?。所以,在编写程序的时候要注意Q能不用二维数组的地方尽量用一l数l,要求内存占用的地方量用一l数l?br /> <br /> <br /> <br /> <br /> <p><strong>4.4.4 启示4Q用HashMap提高内存查询速度</strong></p> <p><strong>田富鹏主~的《大学计机应用基础》中是这hq内存的Q?/strong></p> <p><font face="楷体_GB2312">……</font></p> <p><font face="楷体_GB2312">DRAMQ即内存条。常说的内存q不是内部存储器Q而是DRAM?/font></p> <p><font face="楷体_GB2312">……CPU的运行速度很快Q而外部存储器的读取速度相对来说很慢,如果CPU需要用到的数据L从外部存储器中读取,׃外部讑֤很慢Q?#8230;…QCPU可能用到的数据预先读到DRAM中,CPU产生的(f)时数据也暂时存放在DRAM中,q样的结果是大大的提高了CPU的利用率和计机q行速度?/font></p> <p><font face="楷体_GB2312">……</font></p> <p>q是一个典型计机基础教材针对内存的描qͼ也许作ؓ计算Z业的E序员对q段描述q不陌生。但也因D|qͼ而对内存的处理速度有神话的理解Q认为内存中的处理速度是非常快的?/p> <p>以持有q种观点的程序员遇到一个巨型的内存查询循环的较长时间时Q而束手无{了?/p> <p><strong>L一下如下程序:</strong></p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class MemFor{<br /> <br /> public static void main (String[] args) {<br /> <br /> long start=System.currentTimeMillis(); //取得当前旉<br /> <br /> int len=1024*1024*3;   //讑֮循环ơ数<br /> <br /> int [][] abc=new int[len][2];<br /> <br /> for (int i=0;i<len;i++){<br /> <br /> abc[i][0]=i;<br /> <br /> abc[i][1]=(i+1);<br /> <br /> }<br /> <br /> long get=System.currentTimeMillis();  //取得当前旉<br /> <br /> //循环想要的数值取出来Q本E序取数l的最后一个?br /> <br /> for (int i=0;i<len;i++){<br /> <br /> if ((int)abc[i][0]==(1024*1024*3-1)){<br /> <br /> System.out.println("取值结?"+abc[i][1]);<br /> <br /> }<br /> <br /> }<br /> <br /> long end=System.currentTimeMillis();   //取得当前旉<br /> <br /> //输出试l果<br /> <br /> System.out.println("赋值@环时?"+(get-start)+"ms");<br /> <br /> System.out.println("获取循环旉:"+(end-get)+"ms");<br /> <br /> System.out.print("Java可控内存:");<br /> <br /> System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+"M");<br /> <br /> System.out.print("已占用内?");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> }<br /> <br /> }</pre> </td> </tr> </tbody> </table> q行q个E序Q? <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>java -Xmx1024m MemFor<br /> <br /> </pre> </td> </tr> </tbody> </table> <p><strong>E序的运行结果如下:</strong></p> <p>取值结?3145728</p> <p>赋值@环时?2464ms</p> <p>获取循环旉:70ms</p> <p>Java可控内存:1016M</p> <p>已占用内?128M</p> <p>我们发现Q这个程序@环了3145728ơ获得想要的l果Q@环获取数值的旉用了70毫秒?/p> <p><font face="楷体_GB2312">你觉得快吗?</font></p> <p><font face="楷体_GB2312">是啊Q?0毫秒虽然于1U钟Q但是如果你不得不在q个循环外面再套一个@环,即外层嵌套的@环只?00ơ,那么Q想想看是多毫U呢Q?/font></p> <p><font face="楷体_GB2312">回答Q?0毫秒*100=7000毫秒=7U?/font></p> <p><font face="楷体_GB2312">如果Q@?000ơ呢Q?/font></p> <p><font face="楷体_GB2312">70U!</font></p> <p><font face="楷体_GB2312">70U的q行旉对于q个E序来说是N了?br /> </font> <br /> 面对q个E序的运行时间很多程序员已经束手无策了,其实QJaval程序员们提供了一个较快的查询Ҏ(gu)--哈希表查询?/p> <p>我们这个程序用"HashMap"来改造一下,再看看运行结果:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>import java.util.*;<br /> <br /> public class HashMapTest{<br /> <br /> public static void main (String[] args) {<br /> <br /> HashMap has=new HashMap();<br /> <br /> int len=1024*1024*3;<br /> <br /> long start=System.currentTimeMillis();<br /> <br /> for (int i=0;i<len;i++){<br /> <br /> has.put(""+i,""+i);<br /> <br /> }<br /> <br /> long end=System.currentTimeMillis();<br /> <br /> System.out.println("取值结?"+has.get(""+(1024*1024*3-1)));<br /> <br /> long end2=System.currentTimeMillis();<br /> <br /> System.out.println("赋值@环时?"+(end-start)+"ms");<br /> <br /> System.out.println("获取循环旉:"+(end2-end)+"ms");<br /> <br /> System.out.print("Java可控内存:");<br /> <br /> System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+"M");<br /> <br /> System.out.print("已占用内?");<br /> <br /> System.out.println(Runtime.getRuntime().totalMemory()/1024/1024+"M");<br /> <br /> }<br /> <br /> }</pre> </td> </tr> </tbody> </table> <strong>q行q个E序Q?/strong><br /> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>java -Xmx1024m HashMapTest</pre> </td> </tr> </tbody> </table> <p><strong>E序的运行结果如下:</strong></p> <p>取之l果:3145727</p> <p>赋值@环时?16454ms</p> <p>获取循环旉:0ms</p> <p>Java可控内存:1016M</p> <p>已占用内?566M</p> <p>那么现在用HashMap来取值的旉竟然不到1msQ这时我们的E序的效率明显提高了Q看来用哈希表进行内存中的数据搜索速度实很快?/p> <p>在提高数据搜索速度的同时也要注意到Q赋值时间的差异和内存占用的差异?/p> <p><strong>赋值@环时_</strong></p> <p>HashMapQ?6454ms</p> <p>普通数l:2464ms</p> <p>占用内存Q?/p> <p>HashMapQ?66M</p> <p>普通数l:128M</p> <p>因此Q可以看出HashMap在初始化以及内存占用斚w都要高于普通数l,如果仅仅是ؓ了数据存储,用普通数l是比较适合的,但是Q如果ؓ了频J查询的目的QHashMap是必然的选择?br /> </p> <p><strong>启示5Q用"arrayCopy()"提高数组截取速度</strong></p> <p>当我们需要处理一个大的数l应用时往往需要对数组q行大面U截取与复制操作Q比如针对图形显C的应用时单U的通过Ҏ(gu)l元素的处理操作有时捉襟见肘?/p> <p>提高数组处理速度的一个很好的Ҏ(gu)?System.arrayCopy()"Q这个方法可以提高数l的截取速度Q我们可以做一个对比试验?/p> <p>例如我们用普通的数组赋值方法来处理E序如下Q?/p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public class arraycopyTest1{<br /> <br /> public static void main( String[] args ){<br /> <br /> String temp="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";<br /> <br /> char[] oldArray=temp.toCharArray();<br /> <br /> char[] newArray=null;<br /> <br /> long start=0L;<br /> <br /> newArray=new char[length]; <br /> <br /> //开始时间记?br /> <br /> start=System.currentTimeMillis();<br /> <br /> for(int i=0;i<10000000;i++){<br /> <br /> for(int j=0;j<length;j++){<br /> <br /> newArray[j]=oldArray[begin+j];<br /> <br /> }<br /> <br /> }<br /> <br /> //打印ȝ旉<br /> <br /> System.out.println(System.currentTimeMillis()-start+"ms");<br /> <br /> }<br /> <br /> }<br /> <br /> </pre> </td> </tr> </tbody> </table> E序q行l果如图 3 8所C?br />                               <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/1126040.jpg" alt="" border="0" /><br /> <br /> 那么下面我们再用arrayCopy()的方法试验一下:<br /> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre>public final class arraycopyTest2{<br /> <br /> public static void main( String[] args ){<br /> <br /> String temp="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"<br /> <br /> +"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";<br /> <br /> char[] oldArray=temp.toCharArray(); <br /> <br /> char[] newArray=null; <br /> <br /> long start=0L; <br /> <br /> newArray=new char[length]; <br /> <br /> //记录开始时?br /> <br /> start=System.currentTimeMillis(); <br /> <br /> for(int i=0;i<10000000;i++ ){<br /> <br /> System.arraycopy(oldArray,100,newArray,0,120);<br /> <br /> }<br /> <br /> //打印ȝ旉<br /> <br /> System.out.println((System.currentTimeMillis()-start)+"ms");<br /> <br /> }<br /> <br /> }<br /> <br /> </pre> </td> </tr> </tbody> </table> <p>E序q行l果如图 3 9所C?/p> <p>                         <img src="http://www.tkk7.com/images/blogjava_net/gen-sky/1126041.jpg" alt="" border="0" /><br /> </p> <br /> <p>两个E序的差距再3U多Q如果处理更大批量的数组他们的差距还会更大,因此Q可以在适当的情况下用这个方法来处理数组的问题?/p> <p>有时候我们ؓ了用方便,可以在自qtools包中重蝲一个arrayCopyҎ(gu)Q如下:</p> <table bordercolordark="#ffffff" bordercolorlight="black" width="400" align="center" border="1" cellpadding="2" cellspacing="0"> <tbody> <tr> <td bgcolor="#e6e6e6"> <pre> public static Object[] arrayCopy(int pos,Object[] srcObj){<br /> <br /> return arrayCopy(pos,srcObj.length,srcObj);<br /> <br /> }<br /> <br /> public static Object[] arrayCopy(int pos,int dest,Object[] srcObject){<br /> <br /> Object[] rv=null;<br /> <br /> rv=new Object[dest-pos];<br /> <br /> System.arraycopy(srcObject,pos,rv,0,rv.length);<br /> <br /> return rv;<br /> <br /> }</pre> </td> </tr> </tbody> </table> <br /> <img src ="http://www.tkk7.com/gen-sky/aggbug/285791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/gen-sky/" target="_blank">星期?/a> 2009-07-07 13:19 <a href="http://www.tkk7.com/gen-sky/articles/285791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java和内存有关系 ------------------- 学习自《JavaE序?上班那点事儿?/title><link>http://www.tkk7.com/gen-sky/articles/285787.html</link><dc:creator>星期?/dc:creator><author>星期?/author><pubDate>Tue, 07 Jul 2009 04:38:00 GMT</pubDate><guid>http://www.tkk7.com/gen-sky/articles/285787.html</guid><wfw:comment>http://www.tkk7.com/gen-sky/comments/285787.html</wfw:comment><comments>http://www.tkk7.com/gen-sky/articles/285787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/gen-sky/comments/commentRss/285787.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/gen-sky/services/trackbacks/285787.html</trackback:ping><description><![CDATA[     摘要: 堆和?  栈与堆都是Java用来在内存中存放数据的地斏V?  A.?-用new建立Q垃圾自动回收负责回?     1、堆是一?q行?数据区,cd例化的对象就是从堆上d配空间的Q?     2、在堆上分配I间是通过"new"{指令徏立的Q?   &n...  <a href='http://www.tkk7.com/gen-sky/articles/285787.html'>阅读全文</a><img src ="http://www.tkk7.com/gen-sky/aggbug/285787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/gen-sky/" target="_blank">星期?/a> 2009-07-07 12:38 <a href="http://www.tkk7.com/gen-sky/articles/285787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://sxhnyl.com" target="_blank">޹һɾþþƷۺ </a>| <a href="http://newbuybay.com" target="_blank">ĻƵ</a>| <a href="http://okbala.com" target="_blank">ľþþƷ1</a>| <a href="http://qzllw.com" target="_blank">ѹۿaƵ</a>| <a href="http://lybb16.com" target="_blank">߹ۿxxxx</a>| <a href="http://wwwst6.com" target="_blank">avƬһ</a>| <a href="http://selaohu.com" target="_blank">ƬѹۿĻ</a>| <a href="http://pite2.com" target="_blank">13СϴƵվ</a>| <a href="http://xy996688.com" target="_blank">޹˾Ʒ</a>| <a href="http://97chaopeng2.com" target="_blank">2022Ļ</a>| <a href="http://155562.com" target="_blank">91۲ݹ߹ۿ</a>| <a href="http://tlyyt.com" target="_blank">һƵվ</a>| <a href="http://guhey.com" target="_blank">ͼƬĻ</a>| <a href="http://35419470.com" target="_blank">˳þõӰվ</a>| <a href="http://dxj588.com" target="_blank">ֳִִƵ</a>| <a href="http://wwwvv99.com" target="_blank">޾ƷɫƵ߹ۿԴ</a>| <a href="http://jdvgo.com" target="_blank">avһùŴ</a>| <a href="http://langya2255.com" target="_blank">ձĻһ</a>| <a href="http://www988555.com" target="_blank">99һ</a>| <a href="http://gdfcjzx.com" target="_blank">һëƬѲ</a>| <a href="http://7t53.com" target="_blank">ɫŮһ</a>| <a href="http://aqdav22.com" target="_blank">޸AVľƷԭ</a>| <a href="http://yaboxxx125.com" target="_blank">ѹƵ</a>| <a href="http://hzkjjy.com" target="_blank">ɫƬѹۿ</a>| <a href="http://1ygogo.com" target="_blank">þerƷѹۿ2</a>| <a href="http://xingqiu1.com" target="_blank">avר߹ۿ</a>| <a href="http://jyd56.com" target="_blank">ް߹ۿ</a>| <a href="http://zhongxueping888.com" target="_blank">߹ۿ޾ƷƬ</a>| <a href="http://lai228.com" target="_blank">Դѹۿ</a>| <a href="http://chowngroup.com" target="_blank">ѿ۳ҹվ</a>| <a href="http://58rjz.com" target="_blank">þþþþAVվ</a>| <a href="http://lybb16.com" target="_blank">һһһƬѸ</a>| <a href="http://3838dydy.com" target="_blank">ɫWWW߹ۿ</a>| <a href="http://xmjcjc.com" target="_blank">99þ޾ƷëƬ</a>| <a href="http://sflhb.com" target="_blank">Ļһ</a>| <a href="http://www-715111.com" target="_blank">ձɫѹۿ</a>| <a href="http://fuhui123.com" target="_blank">߹ۿѰƵ</a>| <a href="http://8b22.com" target="_blank">þþþѿӰƬ</a>| <a href="http://sh-shule.com" target="_blank">㽶ѿһ</a>| <a href="http://t66ycom.com" target="_blank">鶹69Ƶ</a>| <a href="http://qu41.com" target="_blank">Ʒר߲</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>