精华内容
下载资源
问答
  • 一个性能问题引出的.net概念

    千次阅读 2004-01-02 13:39:00
    一个性能问题引出的.net概念 关键字:.net 性能 GC 值类型 引用类型 堆 堆栈 string 1 引子 我们先来看一下两组代码,每组中的哪一段代码效率更高呢? 第一组: 代码1: for(int i = 0; i { AddressData ds = new...

    由一个性能问题引出的.net概念

           关键字:.net 性能 GC 值类型 引用类型 堆栈 string

    1        引子

    我们先来看一下两组代码,每组中的哪一段代码效率更高呢?

    第一组:

    代码1

    for(int i = 0; i < 10000; i++)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    {

        AddressData ds = new AddresssData();

        ds = addressS.GetAddress();

    }

     

    代码2

    for(int i = 0; i < 10000; i++)

    {

        AddressData ds;

        ds = addressS.GetAddress();

    }

    第二组:

    代码一:

    string strNames = "@"+Guid.NewGuid().ToString().Replace("-","")+ ",@"+Guid.NewGuid().ToString().Replace("-","")+ ",@"+Guid.NewGuid().ToString().Replace("-","");

    for(int i = 0; i < 10000; i++)

    {

       ……

    }

     

    代码2

    for(int i = 0; i < 10000; i++)

    {

        string strNames = "@"+Guid.NewGuid().ToString().Replace("-","")+ ",@"+Guid.NewGuid().ToString().Replace("-","")+ ",@"+Guid.NewGuid().ToString().Replace("-","");

        ……

    }

    每一组代码中,两段代码实现的功能是一样的,它们之间的区别也很小,但是其效率会相差得惊人,其中一种会很频繁的GC,为什么呢?

    在回答这个问题的时候我们先了解几个.net概念。

    2        什么是GC

    GC的全称是garbage collection,中文名称垃圾回收,是.net中对内存管理的一种功能。垃圾回收器跟踪并回收托管内存中分配的对象,定期执行垃圾回收以回收分配给没有有效引用的对象的内存。当使用可用内存不能满足内存请求时,GC会自动进行。

    在进行垃圾回收时,垃圾回收器回首先搜索内存中的托管对象,然后从托管代码中搜索被引用的对象并标记为有效,接着释放没有被标记为有效的对象并收回内存,最后整理内存将有效对象挪动到一起。这就是GC的四个步骤。

    由上可见,GC是很影响性能的,所以一般说来这种事情况还是尽量少发生为好。

    为了减少一些性能影响,.netGC支持对象老化,或者说分代的概念,代是对象在内存中相对存现时期的度量单位,对象的代数或存现时期说明对象所属的代。目前.net的垃圾回收器支持三代。每进行一次GC,没有被回收的对象就自动提升一代。较近创建的对象属于较新的代,比在应用程序生命周期中较早创建的对象的代数低。最近代中的对象位于零代中。每一次GC的时候,都首先回收零代中的对象,只有在较低代数的对象回收完成后仍不能满足需求的情况下才回收较高代数的对象。

    3        堆栈和堆

    内存有堆栈和堆的概念。堆栈遵循后进先出的原则,后被推入堆栈的对象必定实现本拉出堆栈,这样保证了这部分内存的紧凑,也基本上不需要考虑内存地址的问题。而堆则没有这个原则,任何一个对象都有可能在任何时候进入堆中,也可能在任何时候被移出堆。这样很明显,我们就要考虑每一个对象保存在哪里,所以就需要在堆栈中保存每一个对象保存在堆中的地址。同时在经过一段时间之后我们就会发现堆中产生了许多空隙,也就是碎片,为了提高系统性能,我们这个时候经常需要整理堆,以清除碎片。关于堆栈和堆,如下图所示:

    <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

    4        GC和堆栈、堆

    由前述堆栈和堆的概念可以看出,堆栈不存在垃圾收集的问题,只需要直接压栈即可,而堆,则面临着很复杂的垃圾回收的问题。GC完全是对堆进行操作的,而对堆中对象是否有效的判断则是通过遍历堆栈来实现的。这里涉及到一个引用计数的概念,引用计数是对堆中对象被引用次数的统计,当一个对象的引用计数为零了,那么这个对象就可以被回收了。在进行GC的时候,垃圾回收器遍历堆栈,当发现一个堆地址的时候,它就将堆中该地址上的对象的引用计数加1,然后销毁堆中所有引用计数为零的对象,回收内存并整理堆中的碎片。

    5        值类型和引用类型

    我们都知道,计算机中的数据类型分为值类型和引用类型两种。那么到底什么是值类型什么是引用类型呢?

    大多数编程语言提供内置的数据类型(比如整数和浮点数),这些数据类型会在作为参数传递时被复制(即,它们通过值来传递)。在 .NET Framework 中,这些称为值类型。运行库支持两种值类型:内置值类型和用户定义的值类型。

    引用类型则存储对值的内存地址的引用。引用类型可以是自描述类型、指针类型或接口类型。引用类型的类型可以由自描述类型的值来确定。自描述类型进一步细分成数组和类类型。类类型是用户定义的类、装箱的值类型和委托。

    作为值类型的变量,每个都有自己的数据副本,因此对一个变量的操作不会影响其他变量。作为引用类型的变量可以引用同一对象;因此对一个变量的操作会影响另一个变量所引用的同一对象。

    6        值类型、引用类型和堆栈、堆

    了解了值类型和引用类型,那么,这两种类型在内存中又是怎样表现的呢?

    值类型存储在堆栈中,而引用类型则存储在堆中,然后在堆栈中存储对堆中对象的引用(又叫指针),如下图所示:

    因为这样的一种存储方式,于是就造成了对变量操作影响的不同,例如通过引用指针b对数据所作的更改也会表现在通过引用指针c的得到的数据中。而对值类型进行操作却不会有这样的情况。

    这两种不同也会表现在我们的方式上,例如:

    我们假设ModifyClass()方法是对ClassA中的字段Value12

    ClassA ca = new ClassA()

    ca.Value1 = 2

    ModifyClass(ca)

    int getValue = ca.Value1

        ……

    这时你可以看到getValue的值是4,而ModifyClass()方法并没有返回任何数据。

    而对于值类型,我们就会发现这样做是不可以的,你必须要让方法有返回数据,如:

    int ca = 2

    int getValue = ModifyValue(ca)

    值类型和引用类型的区别还在于声明新变量的时候,如ClassA ca = null是合法的,而int ca = null则是非法的。

    7        类实例化的步骤

    类是最常见也是我们用的最多的一种引用类型,我们知道实例化一个类使用的是一个我们司空见惯的语句:

    ClassA ca = new ClassA()

    那么这短短的一句话中,计算机又做了些什么事情呢?

    实际上,计算机在这个过程中大致做了这么几件事:

    首先,在ClassA ca的时候,生成一个空的引用指针,并将它推入堆栈中:

    然后,在new ClassA()的时候,生成ClassA的新的实例,并放入堆中:

    在赋值号=这一步,将ca的引用指针指向刚刚生成的新实例:

    这个时候,才算完成了整条语句的操作。

    好了,了解了以上这些概念之后,我们可以来回答本文开始的问题了:

    8        回答本文开始的问题

    关于第一组代码,我们首先要了解

    AddressData ds = new AddresssData();

    ds = addressS.GetAddress();

    在内存中的情况,我们已经知道,在上述代码的第一句完成之后,会是这样的一个样子:

    而在第二句代码完成之后,就会变成这样一个样子:

    其中ClassA的实例1是第代码一句产生的,实例2addressS.GetAddress()方法产生的,实例2才是有效的对象,而实例1则不幸落了个一产生就只能等待着被垃圾回收器回收掉的命运。

    一般而言,这种做法不会带来太大的性能问题,但是在某些情况下呢?例如本文一开始演示的这样一个循环?

    这个时候就会在堆中产生非常多的垃圾,占用了大量的内存,于是不得不不断的GC,从而严重影响性能。

    那么对于第二组代码又会怎样呢?

    看起来,第二组代码和第一组代码很不一样,一个是类这种典型的引用类型,而一种是字符串这种通常看起来像是值类型的东西。

    实际上,字符串是一种很特殊的东东,它兼有值类型和引用类型的特征,例如我们必须用这样的方式对他进行处理:

    string ds = “This is a Test”;

    ds = ModifyString(ds);

    其中需要注意的是第二句,这是典型的对值类型进行操作的方式,ModifyString()方法必须要返回数据;但另一方面,我们初始化一个新的字符串变量的时候却又可以这样写:string ds = null。很奇怪对吧,我感觉,之所以会出现这种情况的原因可能是设计者希望它能尽量的和其他的值类型如int,float等数据类型的使用方式一致,毕竟它本身的特征和给我们的感觉是如此的相似,但它却又是无法固定长度的,intfloat等等我们都明确的规定了它是多少位的,string却不行。

    由于这个原因,造成了第二组两段代码之间的性能差异。

    9        一些题外话:一定要用Class吗?

    我们知道Class是引用类型的,struct则是一种值类型,Class是面向对象编程时代所特有的,而我们称作结构的struct则只是面向对象编程萌芽阶段出现的一个实现对象化的一个变通做法,以至于java就抛弃了struct的概念,那么.net为什么没有放弃java放弃了的东西呢?

    struct不是垃圾。首先,struct是一种值类型,这样使得它可以存放在堆栈中,而不是堆中,也就是说,它不会带来GC的性能影响;其次,例如一个对象中有100个元素,如果把这个对象分别定义成类和结构各会占用多少内存空间呢?答案是,定义为类会占用101块内存空间,分别是100个元素和引用指针的;而定义成结构只占用100块而已。也许你会说,才多占用这么一块没什么关系,不过增加了1%而已,那么,如果这个对象只有三个元素呢?

    所以我们可以很明白的得出结论,Class不是唯一。

     

    展开全文
  • 一个PATH引出问题 - 交互式shell和非交换式shell区别。非交互式shell,集群任务投递时,需要留意的一个问题

    一个PATH引出的问题

    用集群投递任务时,发现在Linux的PATH里面设置了变量 export A=“a”,  提交任务到计算节点后,发现变量$A是空,我凌乱了,于是问题来了。。。

    1,任务节点配置相同,提交后怎么没了?
    于是我用qrsh交互式登陆试试,看看能发现什么吗?
    qrsh登陆后,发现$A=a,


    发现不像是任务节点环境的问题,反正他们执行了不一样的东西,难道是非交互运行的问题,于是我做了一下确认


    2,要识别一个shell是否为login shell,只需在该shell下执行echo $0:
    # echo $0
    如果输出为该shell名字,加上一个'-'前缀,则说明该shell为login shell。例如-bash,-su等等。
    输入echo $0,得到的是"bash",说明这不是一个login shell。

    经测试,任务节点确实为非交互式shell


    3,于是我开始找交互式和非交换shell区别
    当bash以login shell启动时,
    它会执行/etc/profile中的命令,然后/etc/profile调用/etc/profile.d目录下的所有脚本;然后执行~/.bash_profile,~/.bash_profile调用~/.bashrc,最后~/.bashrc又调用/etc/bashrc。


    当以非login方式启动时,
    它会调用~/.bashrc,随后~/.bashrc中调用/etc/bashrc,最后/etc/bashrc调用所有/etc/profile.d目录下的脚本。
    于是我查看~/.bashrc 中的$A配置,在其中发现了下面一段代码


    # ~/.bashrc: executed by bash(1) for non-login shells.
    # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
    # for examples
    
    
    # If not running interactively, don't do anything
    [ -z "$PS1" ] && return
    


    也是就是说,如果非交互shell,就return了。下面的代码就不运行了。


    于是呢,我把$A=“a”放在上这部分代码的前面,那非交换shell应该也能运行了

    经测试,发现推理无问题。解决问题

    参考链接  http://www.2cto.com/os/201507/416675.html

    参考链接  http://blog.chinaunix.net/uid-26918227-id-4938474.html

    展开全文
  • 一个C笔试题引出一系列的问题

    千次阅读 2012-03-19 15:37:28
    一个C笔试题引出一系列的问题 下段代码的输出是什么?(这是我做过的一个C笔试题目,当时213了,没有给出完全正确的答案,现在来分析总结一下,防止下次再出现这种213的错误) int main(void) {  int a[] = {6,...

    一个C笔试题引出一系列的问题

    下段代码的输出是什么?(这是我做过的一个C笔试题目,当时213了,没有给出完全正确的答案大哭,现在来分析总结一下,防止下次再出现这种213的错误)

    int main(void)

    {
            int a[] = {6, 7, 8, 9, 10};
            int *p = a;
            *(p++) += 123;   /* 其实没必要把p++扩起来,*和++在同一优先级,从右到左的结合顺序 */

            printf("%d, %d\n", *p, *(++p));


            return 0;
    }

    输出是:8,8

    来解释一下为什么是这个结果,主要注意两个地方:

         1、*(p++) += 123;在这个题目里,这行代码其实是忽悠你的,简化就是p++;

         2、第二点就需要注意函数参数的传递,函数参数传递是通过栈来实现(大部分是通过栈,还有些是通过寄存器),栈的操作方式是FILO,传递参数的时候是第N个参数先入栈,然后是第N-1个,然后.....第1个。为什么不按参数列表的顺序来入栈呢?下面是《C和指针》上的解释:

         虽然像printf("%d, %d\n", *p, *(++p));这样的代码,平常是会被鄙视的,不提倡这样的代码风格和写法,但是作为笔试题还是挺考验基本功的。


    到这里这个题目算是做完了,但是我来深入分析一下:

         1、*(p++) += 123;这行代码产生了什么样的影响?

         a[0] 的值变为129;

         p指针向后移动一个单位。

          ++i和i++有什么区别,++i在i存储的值上增加一并向使用它的表达式"返回"新的(增加后的值);而i++对i增加一,但返回原来的是未增加的值。国内的很多书上都没把这点说清楚 - -|。所以我们这个地方p++只会对下一个语句产生影响。

         2、 a += b 是否和a = a+b等效?

         大部分情况下是等效的,但是也有特例。就是我们下面的情况:

    *(p++) += 123;

         不等效于

    *(p++) = *(p++) + 123;

    如果讲第一行代码替换为第二行,输出结果为 9,9。

    3、函数参数入栈顺序是不是真的与按照参数列表顺序相反呢?口说无凭,来看下实验

    下面是编写的一段测试代码:

    int foo(int i, int j, int k)
    {
            return (i + j + k);
    }
    
    int main(void)
    {
            int a = 1, b = 2, c = 3;
            foo(a, b, c);
            return 0;
    }
    
    然后编译成汇编文件(指令:gcc -c -g -Wa,-adlhn source.c > source.s),我只截取重要的部分:

       9:source.c      ****         int a = 1, b = 2, c = 3;
      50                            .loc 1 9 0
      51 0017 C745FC01              movl    $1, -4(%ebp)
      51      000000
      52 001e C745F802              movl    $2, -8(%ebp)
      52      000000
      53 0025 C745F403              movl    $3, -12(%ebp)
      53      000000
      10:source.c      ****         foo(a, b, c);
      54                            .loc 1 10 0
      55 002c 8B45F4                movl    -12(%ebp), %eax
      56 002f 89442408              movl    %eax, 8(%esp)    /* 把参数c压入到[esp+8] */
      57 0033 8B45F8                movl    -8(%ebp), %eax
      58 0036 89442404              movl    %eax, 4(%esp)    /* 把参数b压入到[esp+4] */
      59 003a 8B45FC                movl    -4(%ebp), %eax
      60 003d 890424                movl    %eax, (%esp)     /* 把参数a压入到[esp],也就是栈顶 */
      61 0040 E8FCFFFF              call    foo
    
    这里的栈是向低地址增长,esp是栈顶指针。对X86的汇编不熟,就暂时分析道这里。



    展开全文
  • 朋友“小平的 fans ”和我讨论一个问题,他发一个文件给我,说 JavaScript 不能取到一个元素的前一个元素。

    朋友“小平的 fans ”和我讨论一个问题,他发一个文件给我,说 JavaScript 不能取到一个元素的前一个元素。

    test.html 代码如下

    <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >

    < html >

        < head >

           < title > test </ title >

           < script type = "text/javascript" >

               function f(){               

                     var sub = document.getElementById( "ME-26934" );

    sub = sub.previousSibling; 

    alert(sub .getAttribute( "id" ) );

             }

        </ script >     

        </ head >

        < body onload = "f();" >

      < input type = "text" id = "ME-26933" value = "aaa" > dddddd </ input >

      < input type = "text" id = "ME-26934" > eeee </ input >

      < input type = "text" id = "ME-26935" > rrr </ input >

        </ body >

    </ html >

    这个问题我遇到过, previousSibling 返回元素之前紧随的兄弟节点。

    元素后面会有一个文本节点,无论它是不是含有文本。所以这里的脚本应修改

    sub = sub .previousSibling .previousSibling;

    alert(sub.getAttribute( "id" ));

    我用的 FireFox3.6 ,试了下,可以了,就发给朋友。

    过了一会儿他回复说, IE6 下还是不行,输出( alert )了空字符串。

    我实验了下,果真不行,看不出来出了什么问题。

    sub = sub.previousSibling.previousSibling;

    alert(sub.nodeType+ ":" +sub.getAttribute( "id" ));

    IE6 输出的是 1:

    1 代表的是元素 element ,这没错啊,取到元素了。

    我首先想到的是令人郁闷的浏览器差异,惯性的想是不是方法兼容问题。

    于是试着换了几个方法、属性,结果都不行。

    正卡壳,忽然想到干嘛这么毫无逻辑的瞎猜,既然有输出(虽然是空字符串),那么方法是可用的,可能是取错了。

    alert(sub.nodeType+ ":" +sub.tagName);

    IE6 下输出的是 1:/INPUT

    发现问题了!

    < input type = "text" id = "ME-26933" value = "aaa" > dddddd </ input >

    IE6 下这种书写格式,同级节点分别是: <input> 元素、 </input> 元素 、文本节点。

    FireFox3.6 <input> 元素 &</input> 元素算一个元素。

    如此,问题迎刃而解。整理后的文档如下:

    test.html 文件

    <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >

    < html >

        < head >

           < title > test </ title >

           < script type = "text/javascript" >

               function f(){               

                     var sub = document.getElementById( "ME-26934" );

                      sub = sub.previousSibling.previousSibling; 

    alert(sub.nodeType+ ":" +sub.tagName+ ":" +sub.getAttribute( "id" ));

                   

                     var sub1 = document.getElementById( "ME-26935" );

                     sub1 = sub1.previousSibling.previousSibling;

    alert(sub1.nodeType+ ":" +sub1.tagName);

             }

        </ script >     

        </ head >

        < body onload = "f();" >

      < input type = "text" id = "ME-26933 " value = "aaa" /> dddddd

      < input type = "text" id = "ME-26934" > eeee </ input >

      < input type = "text" id = "ME-26935" > rrr </ input >

        </ body >

    </ html >

     

    第一个 alert 1:INPUT: ME-26933

    第二个 alert 1:/INPUT

     

    小结: 1. < input type = "text" id = "ME-26933" value = "aaa" > dddddd </ input >

    IE6 下这种书写格式,同级节点分别是: <input> 元素、 </input> 元素、文本节点。

    2. 分析问题要条理清晰,步步为营,而不是“投机式”的试错,虽然有些时候“投机式”方法能够快速的解决问题,但分析问题就不太适用了,什么问题用什么方法。

     

    展开全文
  • 系统平台:ThinkPad T60(Centrino Duo 1.83G,2G DDR667,80G SATA,ATI X1400)操作系统: 正版Microsoft Windows XP [版本 5.1.2600]问题:1...近日出现问题:在windows的右下角启动栏里面,使用以上任意一个连接都可
  • 在Delphi中按值传递的函数(过程)是这样定义的:procedure fillsomething (Xvalue : integer)按值传递是无法改变实参的值的。按地址传递的函数(过程)是这样[定义的:...可是由于Delphi中向系统申请一个变量和向系
  • 一.故障说明 前段时间一朋友遇到的案例,根据他的... 朋友说一个大事务不能完成回滚操作,系统异常。 查看等待事件,如下图: 这里的row cache lock 较为严重。 row cache lock 对应的cache#=11,对应的child latc
  • 梦中没有错与对,梦中没有恨和悔......四年多前的一个往事大约在2010年的时候,我排查了一个问题问题描述如下:服务端:Linux Kernel 2.6.8/192.168.188.100客户端:Windows XP/192.168.40.34业务流程
  • 对象迁移表空间引出的三问题

    千次阅读 2016-03-04 18:21:21
    我们有一个开发库,默认表空间是TEST_TBS,但今天查看开发库的时候,发现有些表和字段并不在用户默认使用的表空间中,而在USERS表空间,之所以可能是之前开发人员执行SQL是从其他库复制过来的,连通tablespace USERS...
  • 我们公司的项目都是前后端分离的,上线几个月以来,发现一个很奇怪的问题,每次前端发起请求,通过浏览器的开发者工具都能看到在Network下同一个url有两条请求,第一条请求的Method为OPTIONS,第二条请求的Method才...
  • 引出“Java的synchronized锁问题

    千次阅读 2021-04-14 21:43:21
    关于下面段代码,以下说法正确的是: public class Test { private synchronized void a() { } private void b() { synchronized (this) { } } private synchronized static void c() { } private void d...
  • ORA-12519引出问题

    千次阅读 2013-09-14 12:22:02
    看到这篇帖子提到一个ORA-12519的问题处理: http://blog.csdn.net/diguoguo/article/details/6185536 oerr的解释: 12519, 00000, "TNS:no appropriate service handler found" // *Cause: The listener ...
  • 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。 引出的递归 和非递归的探讨
  • 由使用LeakDialog时遇到的问题引出的一些分析 前段时间在使用leakDialog检测调用malloc和new所分配的内存泄露时,发现其根本不起作用!这让我百思不得其解!周末有时间研究了一下终于弄清了原因所在。本着分享的...
  • 问题的现象: 使用DHC工具发送请求,Nginx能够正常接到请求并转发,但是tomcat中的日志一直没有打印出来,说明Nginx是正常的,是tomcat没有响应请求,说明此时tomcat处于无法访问(假死)状态。 因为个人对tomcat...
  • eclipse Installed JREs 配置引出问题

    万次阅读 2010-11-15 11:44:00
    本人在学习java6新特性的时候,发现了一个由 eclipse Installed JREs 配置引出问题。代码如下 import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools....
  • Session的时效性——由验证码引出问题  (对jsp servlet tomcat 的理解) 目录 Session的时效性——由验证码引出问题 1 1、理解JSP、servlet、web... 2、好了,当一切准备工作做完,来看一个结合三者的例
  • 由web项目中上传图片所引出的路径问题
  • 由Object.clone()引出的protected权限问题

    千次阅读 2018-05-10 10:16:34
    Object.clone()大家可能不太理解由Object.clone()而引出的protected权限问题这句话,那我们先看一段代码: 第一个类CloneClassOne package com.ustc.sup; public class CloneClassOne { }123第二个类CloneClassTwo ...
  • 今天在写一个JSP页面时候,发现下面报错: 测试URL传参  通常情况下,通过使用contentType和下面的就可以解决传参过程中的中文乱码问题,但是貌似URL传参还要设备别的东西。 request.set...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,869
精华内容 42,747
关键字:

一个问题引出