Mar1

【学习笔记】PHP中copy on write写时复制机制

Author: leeon  Click: 5528   Comments: 0 Category: php  Tag: php,写时复制,数组

什么是写时复制(Copy On Write)?

答:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作;而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作。

这个技术需要跟虚拟内存和分页同时使用,好处就是在执行复制操作时因为不是真正的内存复制,而只是建立了一个指针,因而大大提高效率。但这不是一直成立的,如果在复制新对象之后,大部分对象都还需要继续进行写操作会产生大量的分页错误,得不偿失。所以COW高效的情况只是在复制新对象之后,在一小部分的内存分页上进行写操作。

     在PHP 内核中同样使用了写时复制机制来避免在赋值时导致内存增加,比如我们在使用foreach循环体时,可以发现其中的奥秘,示例代码:

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]

当我们执行此代码时会得到内存占用为:788 

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]

当我们取消 //$v='aaaaaaaaaaaaaa';  的注释,此时内存占用数值为:840,注意内存增长了。

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as &$v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]


当我们将foreach中的$v 改写为 &$v 时,不管是否注释循环体中对$v的注释,我们都可以得到内存占用为:788

这里就说明了COW机制的介入,当我们在foreach循环中纯粹的只用到对$v 的读操作时,PHP内核会将$v这个变量的内存地址指向到$arr中数组这一索引的内存地址,并没有将数组中的数据复制一份给到变量$v,此时内存占用情况和使用&$v 是一样的。但当我们在循环体内对$v进行写操作时,写时复制机制就被激活了,此时PHP会重新开辟一段内存空间给到$v变量,而将原先$v指向数组的内存地址给断开了,此时内存必然就会增长了。

这里可以得出另外一个结论:当我们在读取大数据的时候,要注意COW机制引入的内存增长影响,同样避免不必要的对变量写,可以提高代码运行性能。

Feb16

【原创】Eclipse集成javap查看字节码

Author: leeon  Click: 7259   Comments: 0 Category: java  Tag: javap,eclipse,java,字节码

     分析java语言特性的一个好帮手是使用javap工具查看java编译后的字节码,楼主今天在学习java泛型中的桥方法时遇到一些不解,想到javap这个好工具可以帮助解答一些疑惑,索性就捣鼓如何在eclipse中配置javap工具快速查看java字节码。

    楼主学习的代码工程用的maven结构。默认java编译后的class文件是放在: 工程目录/target/classes 下的,故在配置javap的时候需要配置的变量有所不同,不能直接参考网上的教程方式:

   首先进入run -> External Tool -> External Tools Configurations 然后在Program 节点选定后右键点击“New” 创建一个新的扩展工具配置。

 

然后按照如下图所示配置即可:

 

Location:指定javap的绝对路径。

Working Directory: ${project_loc}变量返回工程所在的绝对路径。

Arguments: 注意这里的参数配置,-classpath 指定的是java代码编译后class文件存放的目录,这里我们配置的是相对于工程根目录而言,class文件的相对目录路径,-c参数后面的值是指定要查看哪个文件的字节码,${java_type_name} 变量返回你选取的类文件名。使用javap工具之前一定得获取class文件,因此先让你的代码能正常run一遍把。

如果你的工程不是maven的目录结构,那么只用按照本文配置修改classpath参数的值指定你的class文件存放的相对路径即可。使用javap工具的时候切记需要激活你当前java的代码编辑窗口才能使用。

Feb9

【学习笔记】Java基本数据类型数组与Object的转换

Author: leeon  Click: 6209   Comments: 0 Category: java  Tag: java,object,array,数组

在阅读java核心技术第一卷时有一个技术细节值得记录一下:

基本数据类型数组和Object类型是可以互相转换的,但是基本数据类型不能和Object[]对象型数组进行转换

简言之: 在java中数组是对象,对象数组和原始数据类型数组在使用方法上几乎是完全一致的,唯一的差别在于对象数组容纳的是引用而原始数据类型数组容纳的是具体的数值

比如如下代码:

[code="java"]

import java.util.Arrays;



public class test {
private static void r(Object o){
System.out.println(Arrays.toString((int[])o));
}
/**
* @param args
*/
public static void main(String[] args) {
int[] a = new int[10];
r(a);


}

}
[/code]

我们可以看到输出结果为:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

但我们不能将静态方法r中的参数类型申明为Object[] ,这样是编译不通过的。

在非基本类型数组与Object之间的转换时我们可以使用Object做为参数类型,也可以使用Object[]做为参数类型,其中的区别可以参考如下代码:

[code="java"]

class Student{
String name="zhang";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


public class test {
private static void r1(Object o){
for(Object obj : (Object[])o){
System.out.println(((Student)obj).getName());
}
}

private static void r2(Object[] o){
for(Object obj : o){
System.out.println(((Student)obj).getName());
}
}

public static void main(String[] args) {
Student[] student = {new Student(),new Student()};
r1(student);
r2(student);
}

}
[/code]

输出结果是一样的。

Feb6

【转载】c++中typeid与type_info

Author: leeon  Click: 7505   Comments: 0 Category: c/c++  Tag: typeid,cpp,type_info,c++

     在学习java中的Class类,有getClass方法,其特性与c++中的typeid很类似,java中调用getClass方法和c++中的typeid运算符等价。

     typeid是C++的一个关键字,其作用是在程序运行时,返回对象的类型,即所谓的RTTI(Run Time Type Identification), 它使程序能够获取由指针或引用所指向的对象的实际类型,即允许“用指向基类的指针或引用来操作对象”的程序能够获取到“这些指针或引用所指对象”的实际派生类型。在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid。

typeid操作符的返回结果是名为type_info的标准库类型的对象的引用。 type_info在typeinfo头文件中定义:


class type_info {public:
  virtual ~type_info();
  bool operator== (const type_info& rhs) const;
  bool operator!= (const type_info& rhs) const;
  bool before (const type_info& rhs) const;
  const char* name() const;private:
  type_info (const type_info& rhs);
  type_info& operator= (const type_info& rhs);
}; 

如下内容摘自http://www.cplusplus.com/reference/typeinfo/type_info/:


typeid can be applied to any typed expression, including a type itself, to retrieve the its type_info.

When typeid is applied to a reference or dereferenced pointer to an object of a polymorphic class type (a class declaring or inheriting a virtual function), it considers its dynamic type (i.e., the type of the most derived object). This requires the RTTI (Run-time type information) to be available.

When typeid is applied to a dereferenced null pointer a bad_typeid exception is thrown.


type_info成员介绍如下:


operator==
operator!=
Comparison operators. They return whether the two types describe the same type.
A derived type is not considered the same type as any of its base classes.
before
Returns true if the type precedes the type of rhs in the collation order.
The collation order is just an internal order kept by a particular implementation and is not necessarily related to inheritance relations or declaring order.
name
Returns a null-terminated character sequence with a human-readable name for the type.
copy constructor and copy operator
These are private, preventing type_info values from being copiable.

示例代码:

[code="cpp"]
// type_info example
#include <iostream>
#include <typeinfo>
using namespace std;

struct Base {};
struct Derived : Base {};
struct Poly_Base {virtual void Member(){}};
struct Poly_Derived: Poly_Base {};

int main() {
// built-in types:
int i;
int * pi;
cout << "int is: " << typeid(int).name() << endl;
cout << " i is: " << typeid(i).name() << endl;
cout << " pi is: " << typeid(pi).name() << endl;
cout << "*pi is: " << typeid(*pi).name() << endl << endl;

// non-polymorphic types:
Derived derived;
Base* pbase = &derived;
cout << "derived is: " << typeid(derived).name() << endl;
cout << " *pbase is: " << typeid(*pbase).name() << endl;
cout << boolalpha << "same type? ";
cout << ( typeid(derived)==typeid(*pbase) ) << endl << endl;

// polymorphic types:
Poly_Derived polyderived;
Poly_Base* ppolybase = &polyderived;
cout << "polyderived is: " << typeid(polyderived).name() << endl;
cout << " *ppolybase is: " << typeid(*ppolybase).name() << endl;
cout << boolalpha << "same type? ";
cout << ( typeid(polyderived)==typeid(*ppolybase) ) << endl << endl;
}
[/code]

输出:

[code="plain"]
int is: int
i is: int
pi is: int *
*pi is: int

derived is: struct Derived
*pbase is: struct Base
same type? false

polyderived is: struct Poly_Derived
*ppolybase is: struct Poly_Derived
same type? true
[/code]

分类

标签

归档

最新评论

Abyss在00:04:28评论了
Linux中ramdisk,tmpfs,ramfs的介绍与性能测试
shallwe99在10:21:17评论了
【原创】如何在微信小程序开发中正确的使用vant ui组件
默一在09:04:53评论了
Berkeley DB 由浅入深【转自架构师杨建】
Memory在14:09:22评论了
【原创】最佳PHP框架选择(phalcon,yaf,laravel,thinkphp,yii)
leo在17:57:04评论了
shell中使用while循环ssh的注意事项

我看过的书

链接

其他

访问本站种子 本站平均热度:8823 c° 本站链接数:1 个 本站标签数:464 个 本站被评论次数:94 次