php各数据类型占用空间 php占用内存过高

数据库包括哪些?问题一:数据库系统包括什么?通常由软件、数据库和数据管理员组成 。
问题二:请问数据库有哪些种类呢?根据存储模型划分,数据库类型主要可分为:网状数据库(Network Database)、关系数据库(Relational Database)、树状数据库(Hierarchical Database)、面向对象数据库(Object-oriented Database)等 。商业应用中主要是关系数据库,比如Oracle、DB2、Sybase、MS SQL Server、Informax、MySQL等 。全部罗列出来是没有意义的,数据库太多了,你不说你的工作是涉及哪方面,恐怕很难提供更适合你的数据库 。
初级应用一般是ACCESS 配合的脚本程序一般是 ASP ASP.NET JSPMICROSOFT SQL 比较复杂点 不过功能强大很多 配合的脚本和ACCESS的一样MYSQL和PHP的组合是比较完美的如果你需要处理1000W条数据以上级别的数据,那以上的都不合适,一般用的比较多的是ORACLE 这个入门难度非常大如果想学的话就先学MICROSOFT SQL吧,这个网上教学比较多,ASP.NET 2.0,应用的是非常广泛的 。
问题三:sql数据类型有哪些一、 整数数据类型
整数数据类型是最常用的数据类型之一 。
1、INT (INTEGER)
INT (或INTEGER)数据类型存储从-2的31次方 (-2 , 147 , 483 ,648) 到2的31次方-1 (2,147 , 483,647) 之间的所有正负整数 。每个INT 类型的数据按4 个字节存储,其中1 位表示整数值的正负号,其它31 位表示整数值的长度和大小 。
2、SMALLINT
SMALLINT 数据类型存储从-2的15次方( -32,768) 到2的15次方-1( 32 ,767 )之间的所有正负整数 。每个SMALLINT 类型的数据占用2 个字节的存储空间 , 其中1 位表示整数值的正负号,其它15 位表示整数值的长度和大小 。
3、TINYINT
TINYINT数据类型存储从0 到255 之间的所有正整数 。每个TINYINT类型的数据占用1 个字节的存储空间 。
4、BIGINT
BIGINT 数据类型存储从-2^63 (-9 ,223,372,036,854, 775,807) 到2^63-1( 9 , 223,372 , 036,854 , 775,807) 之间的所有正负整数 。每个BIGINT 类型的数据占用8个字节的存储空间 。
二、 浮点数据类型
浮点数据类型用于存储十进制小数 。浮点数值的数据在SQL Server 中采用上舍入(Round up 或称为只入不舍)方式进行存储 。所谓上舍入是指,当(且仅当)要舍入的数是一个非零数时,对其保留数字部分的最低有效位上的数值加1,并进行必要的进位 。若一个数是上舍入数 , 其绝对值不会减少 。如:对3.14159265358979 分别进行2 位和12位舍入,结果为3.15 和3.141592653590 。
1、REAL 数据类型
REAL数据类型可精确到第7 位小数 , 其范围为从-3.40E -38 到3.40E38 。每个REAL类型的数据占用4 个字节的存储空间 。
2、FLOAT
FLOAT数据类型可精确到第15 位小数,其范围为从-1.79E -308 到1.79E308 。每个FLOAT 类型的数据占用8 个字节的存储空间 。FLOAT数据类型可写为FLOAT[ n ]的形式 。n 指定FLOAT 数据的精度 。n 为1到15 之间的整数值 。当n 取1 到7 时 , 实际上是定义了一个REAL 类型的数据,系统用4 个字节存储它;当n 取8 到15 时,系统认为其是FLOAT 类型 , 用8 个字节存储它 。
3、DECIMAL
DECIMAL数据类型可以提供小数所需要的实际存储空间,但也有一定的限制,您可以用2 到17 个字节来存储从-10的38次方-1 到10的38次方-1 之间的数值 。可将其写为DECIMAL[ p [s] ]的形式,p 和s 确定了精确的比例和数位 。其中p 表示可供存储的值的总位数(不包括小数点),缺省值为18; s 表示小数点后的位数,缺省值为0 。例如:decimal (15 5),表示共有15 位数,其中整数10 位,小数5 。位表4-3 列出了各精确度所需的字节数之间的关系 。
4、NUMERIC
NUMERIC数据类型与DECIMAL数据类型完全相同 。
注意:SQL Server 为了和前端的开发工具配合,其所支持的数据精度默认最大为28位 。
三、 二进制数据类型
1、BINARY
BINARY 数据类型用于存储二进制数据 。其定义形式为BINARY( n),n 表示数据的长度,取值为1 到......
问题四:常用数据库有哪些?1. IBM 的DB2
作为关系数据库领域的开拓者和领航人,IBM在1997年完成了System R系统的原型,1980年开始提供集成的数据库服务器―― System/38,随后是SQL/DSforVSE和VM , 其初始版本与SystemR研究原型密切相关 。DB2 forMVSV1 在1983年推出 。该版本的目标是提供这一新方案所承诺的简单性,数据不相关性和用户生产率 。1988年DB2 for MVS 提供了强大的在线事务处理(OLTP)支持,1989 年和1993 年分别以远程工作单元和分布式工作单元实现了分布式数据库支持 。最近推出的DB2 Universal Database 6.1则是通用数据库的典范,是第一个具备网上功能的多媒体关系数据库管理系统,支持包括Linux在内的一系列平台 。
2. Oracle
Oracle 前身叫SDL,由Larry Ellison 和另两个编程人员在1977创办,他们开发了自己的拳头产品,在市场上大量销售,1979 年,Oracle公司引入了第一个商用SQL 关系数据库管理系统 。Oracle公司是最早开发关系数据库的厂商之一,其产品支持最广泛的操作系统平台 。目前Oracle关系数据库产品的市场占有率名列前茅 。
3. Informix
Informix在1980年成立,目的是为Unix等开放操作系统提供专业的关系型数据库产品 。公司的名称Informix便是取自Information 和Unix的结合 。Informix第一个真正支持SQL语言的关系数据库产品是Informix SE(StandardEngine) 。InformixSE是在当时的微机Unix环境下主要的数据库产品 。它也是第一个被移植到Linux上的商业数据库产品 。
4. Sybase
Sybase公司成立于1984年,公司名称“Sybase”取自“system”和 “database” 相结合的含义 。Sybase公司的创始人之一Bob Epstein 是Ingres 大学版(与System/R同时期的关系数据库模型产品)的主要设计人员 。公司的第一个关系数据库产品是1987年5月推出的Sybase SQLServer1.0 。Sybase首先提出Client/Server 数据库体系结构的思想,并率先在Sybase SQLServer 中实现 。
5. SQL Server
1987 年,微软和 IBM合作开发完成OS/2,IBM 在其销售的OS/2 ExtendedEdition 系统中绑定了OS/2Database Manager,而微软产品线中尚缺少数据库产品 。为此,微软将目光投向Sybase,同Sybase 签订了合作协议,使用Sybase的技术开发基于OS/2平台的关系型数据库 。1989年,微软发布了SQL Server 1.0 版 。
6. PostgreSQL
PostgreSQL 是一种特性非常齐全的自由软件的对象――关系性数据库管理系统(ORDBMS),它的很多特性是当今许多商业数据库的前身 。PostgreSQL最早开始于BSD的Ingres项目 。PostgreSQL 的特性覆盖了SQL-2/SQL-92和SQL-3 。首先,它包括了可以说是目前世界上最丰富的数据类型的支持;其次 , 目前PostgreSQL 是唯一支持事务、子查询、多版本并行控制系统、数据完整性检查等特性的唯一的一种自由软件的数据库管理系统.
......
问题五:数据库的对象有哪些Funciton:函数
Procedure:存储过程
Package:代码包,一个包里面 , 定义多个存储过程、函数、类型、常量等
Type:自定义数据类型
Trigger:触发器
Job:数据库作业 (定期执行的)
Table:表
Index:索引
Constraint:约束,限制各数据项应满足哪些限阀条件
View:视图
Materialized View:物化视图
Sequence:序列
User:叫 用户
Synonym:同义词
Database link:数据库链接(ORACLE有,别的数据库不熟 , 想必也应该有,可能不叫这个名字)
TableSpace:表空间(ORACLE叫这个名字,别的数据库不熟)
CURSOR:游标
常用的大致这些 , 可能会有遗漏 , 但也应该不会差太多 。
问题六:常用数据库有哪些?他们有什么区别开源的Mysql顶;PostgreSQL即开放源码的
商业的Oracle/SQL Server/DB2即收费的
问题七:查看数据库中有哪些表空间可以用S罚L语句 SELECT ** FROM v$tablespace
也可以用oracle enterprise manger console 直接在可视化窗口上查看
问题八:常见的数据库应用系统有哪些?现在极大多的企业级软件都是基于数据库的 。
比如:
ERP: 企业资源管理计划
CRM: 客户关系管理
OA: 办公自动化 。
12306铁道部的网上订票系统 。
。。。
问题九:如何看mysql都有哪些数据库第一步:首先是查看mysql数据库的端口号,使用命令show
第二步:查看有哪些数据库,
第三步:查看mysql数据库所有用户,
第四步:查看某个数据库中所有的表
问题十:数据库系统包括什么?通常由软件、数据库和数据管理员组成 。
php怎么查看一个变量的占用内存我们在前面的php高效写法提到,尽量不要复制变量,特别是数组 。一般来说 , PHP数组的内存利用率只有 1/10, 也就是说 , 一个在C语言里面100M 内存的数组,在PHP里面就要1G 。下面我们可以粗略的估算PHP数组占用内存的大小,首先我们测试1000个元素的整数占用的内存:
[php] view plain copy print?
?php
echo memory_get_usage() , 'br';
$start = memory_get_usage();
$a = Array();
for ($i=0; $i1000; $i) {
$a[$i] = $i$i;
}
$mid =memory_get_usage();
echo memory_get_usage() , 'br';
for ($i=1000; $i2000; $i) {
$a[$i] = $i$i;
}
$end =memory_get_usage();
echo memory_get_usage() , 'br';
echo 'argv:', ($mid - $start)/1000 ,'bytes' , 'br';
echo 'argv:',($end - $mid)/1000 ,'bytes' , 'br';
输出是:
353352
437848
522024
argv:84.416bytes
argv:84.176bytes
大概了解1000
个元素的整数数组需要占用 82k 内存 , 平均每个元素占用 84 个字节 。而纯 C 中整体只需要 4k(一个整型占用4byte * 1000
) 。memory_get_usage() 返回的结果并不是全是被数组占用了,还要包括一些 PHP
运行本身分配的一些结构,可能用内置函数生成的数组更接近真实的空间:
[php] view plain copy print?
?php
$start = memory_get_usage();
$a = array_fill(0, 10000, 1);
$mid = memory_get_usage(); //10k elements array;
echo 'argv:', ($mid - $start )/10000,'byte' , 'br';
$b = array_fill(0, 10000, 1);
$end = memory_get_usage(); //10k elements array;
echo 'argv:', ($end - $mid)/10000 ,'byte' , 'br';
得到:
argv:54.5792byte
argv:54.5784byte
从这个结果来看似乎一个数组元素大约占用了54个字节左右 。
首先看一下32位机C语言各种类型占用的字节:
[cpp] view plain copy print?
#include "stdafx.h"
//#include stdio.h
int main() {
printf("int:%d\nlong:%d\ndouble:%d\nchar*:%d\nsize_t:%d\n",
sizeof(int), sizeof(long),
sizeof(double), sizeof(char *),
sizeof(size_t));
return0;
}
int:4
long:4
double:8
har*:4
size_t:4
在PHP中都使用long类型来代表数字 , 没有使用int类型
大家都明白PHP是一种弱类型的语言,它不会去区分变量的类型,没有int float char *之类的概念 。
我们看看php在zend里面存储的变量,PHP中每个变量都有对应的 zval, Zval结构体定义在Zend/zend.h里面,其结构:
[cpp] view plain copy print?
typedef struct _zval_struct zval;
struct _zval_struct {
/* Variable information */
zvalue_value value;/* The value 1 12字节(32位机是12,64位机需要8 4 4=16) */
zend_uint refcount__gc; /* The number of references to this value (for GC) 4字节 */
zend_uchar type;/* The active type 1字节*/
zend_uchar is_ref__gc;/* Whether this value is a reference () 1字节*/
};
PHP使用一种UNION结构来存储变量的值,即zvalue_value 是一个union,UNION变量所占用的内存是由最大
成员数据空间决定 。
[cpp] view plain copy print?
typedef union _zvalue_value {
long lval;/* long value */
double dval;/* double value */
struct {/* string value */
char *val;
int len;
} str;
HashTable *ht;/* hash table value */
zend_object_value obj;/*object value */
} zvalue_value;
最大成员数据空间是struct str,指针占*val用4字节,INT占用4字节,共8字节 。
struct zval占用的空间为8 4 1 1 = 14字节 ,
其实呢,在zval中数组,字符串和对象还需要另外的存储结构,数组则是一个 HashTable:
HashTable结构体定义在Zend/zend_hash.h.
[cpp] view plain copy print?
typedef struct _hashtable {
uint nTableSize;//4
uint nTableMask;//4
uint nNumOfElements;//4
ulong nNextFreeElement;//4
Bucket *pInternalPointer;/* Used for element traversal 4*/
Bucket *pListHead;//4
Bucket *pListTail;//4
Bucket **arBuckets;//4
dtor_func_t pDestructor;//4
zend_bool persistent;//1
unsigned char nApplyCount;//1
zend_bool bApplyProtection;//1
#if ZEND_DEBUG
int inconsistent;//4
#endif
} HashTable;
HashTable 结构需要 39 个字节 , 每个数组元素存储在 Bucket 结构中:
[cpp] view plain copy print?
typedef struct bucket {
ulong h;/* Used for numeric indexing4字节 */
uint nKeyLength;/* The length of the key (for string keys)4字节 */
void *pData;/* 4字节*/
void *pDataPtr;/* 4字节*/
struct bucket *pListNext;/* PHP arrays are ordered. This gives the next element in that order4字节*/
struct bucket *pListLast;/* and this gives the previous element4字节 */
struct bucket *pNext;/* The next element in this (doubly) linked list4字节*/
struct bucket *pLast;/* The previous element in this (doubly) linked list4字节*/
char arKey[1];/* Must be last element1字节*/
} Bucket;
Bucket
结构需要 33 个字节 , 键长超过四个字节的部分附加在 Bucket 后面,而元素值很可能是一个 zval 结构,另外每个数组会分配一个由
arBuckets 指向的 Bucket 指针数组,虽然不能说每增加一个元素就需要一个指针,但是实际情况可能更糟 。这么算来一个数组元素就会占用
54 个字节,与上面的估算几乎一样 。
一个空数组至少会占用 14(zval)39(HashTable)33(arBuckets) = 86
个字节,作为一个变量应该在符号表中有个位置 , 也是一个数组元素,因此一个空数组变量需要 118
个字节来描述和存储 。从空间的角度来看,小型数组平均代价较大 , 当然一个脚本中不会充斥数量很大的小型数组,可以以较小的空间代价来获取编程上的快捷 。但如果将数组当作容器来使用就是另一番景象了 , 实际应用经常会遇到多维数组,而且元素居多 。比如10k个元素的一维数组大概消耗540k内存,而10k
x 10 的二维数组理论上只需要 6M 左右的空间 , 但是按照 memory_get_usage
的结果则两倍于此,[10k,5,2]的三维数组居然消耗了23M,小型数组果然是划不来的 。
PHP中有几种主要的数据类型,通俗的解释一下他们数据类型有三种:
1.标量数据类型
标量数据类型包括以下几种 。
(1)boolean:布尔型
布尔变量是PHP变量中最简单的 。它保存一个True或者False值 。其中True或者False是PHP的内部关键字 。设定一个布尔型的变量,只需将True或者False赋值给该变量
(2)string:字符串
字符串是连续的字符序列,字符串中的每个字符只占用一个字节 。在PHP中,定义字符串有3种方式:
单引号方式,
双引号方式 ,
Heredoc方式 。
(3)integer:整数
整数数据类型只能包含整数 。这些数据类型可以是正数或负数 。在32位的操作系统中,有效的范围是?2 147 483 648~ 2 147 483 647 。
(4)double:浮点数
浮点数据类型可以用来存储数字,也可以保存小数 。它提供的精度不整数大得多 。在32位的操作系统中,有效的范围是1.7E-308~1.7E 308 。
2.复合数据类型
复合数据类型包括以下两种 。
(1)array:数组
可以是二维、三维或者多维,数组中的各元素可以是string、integer或double,也可以是array 。
(2)object:对象类型
3.特殊数据类型
特殊数据类型包括以下两种 。
(1)resource:资源
资源是PHP内的几个函数所需要的特殊数据类型 , 由编程人员来分配 。
(2)null:空值
空值是最简单的数据类型 。表示没有为该变量设置任何值,另外,空值(NULL)不区分大小写 。
解析PHP中的内存管理,PHP动态分配和释放内存本篇文章是对PHP中php各数据类型占用空间的内存管理 PHP动态分配和释放内存进行php各数据类型占用空间了详细的分析介绍 需要的朋友参考下
摘要 内存管理对于长期运行的程序 例如服务器守护程序 是相当重要的影响 因此 理解PHP是如何分配与释放内存的对于创建这类程序极为重要 本文将重点探讨PHP的内存管理问题
一 内存在PHP中 填充一个字符串变量相当简单 这只需要一个语句"<?php $str = hello world ; ?>"即可 并且该字符串能够被自由地修改 拷贝和移动 而在C语言中 尽管你能够编写例如"char *str = "hello world ";"这样的一个简单的静态字符串 但是 却不能修改该字符串 因为它生存于程序空间内 为了创建一个可操纵的字符串 你必须分配一个内存块 并且通过一 个函数(例如strdup())来复制其内容
复制代码代码如下: { char *str; str = strdup("hello world"); if (!str) { fprintf(stderr "Unable to allocate memory!"); } }
由于后面我们将分析的各种原因 传统型内存管理函数(例如malloc() free() strdup() realloc() calloc() 等等)几乎都不能直接为PHP源代码所使用
二 释放内存在几乎所有的平台上 内存管理都是通过一种请求和释放模式实现的 首先 一个应用程序请求它下面的层(通常指"操作系统") "我想使用一些内存空间" 如果存在可用的空间 操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序 当 应用程序使用完这部分内存 它应该被返回到OS 这样以来 它就能够被继续分配给其它程序 如果该程序不返回这部分内存 那么OS无法知道是否这块内存不 再使用并进而再分配给另一个进程 如果一个内存块没有释放 并且所有者应用程序丢失了它 那么 我们就说此应用程序"存在漏洞" 因为这部分内存无法再为 其它程序可用 在一个典型的客户端应用程序中 较小的不太经常的内存泄漏有时能够为OS所"容忍" 因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS 这并没有什么 因为OS知道它把该内存分配给了哪个程序 并且它能够确信当该程序终止时不再需要该内存 而对于长时间运行的服务器守护程序 包括象Apache这样的web服务器和扩展php模块来说 进程往往被设计为相当长时间一直运行 因为OS不能清理内存使用 所以 任何程序的泄漏 无论是多么小 都将导致重复操作并最终耗尽所有的系统资源 现 在 我们不妨考虑用户空间内的stristr()函数 为了使用大小写不敏感的搜索来查找一个字符串 它实际上创建了两个串的各自的一个小型副本 然后执 行一个更传统型的大小写敏感的搜索来查找相对的偏移量 然而 在定位该字符串的偏移量之后 它不再使用这些小写版本的字符串 如果它不释放这些副本 那 么 每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存 最后 web服务器进程将拥有所有的系统内存 但却不能够使用它 你可以理直气壮地说 理想的解决方案就是编写良好 干净的 一致的代码 这当然不错 但是 在一个象PHP解释器这样的环境中 这种观点仅对了一半
三 错误处理为了实现"跳出"对用户空间脚本及其依赖的扩展函数的一个活动请求 需要使用一种方法来 完全"跳出"一个活动请求 这是在Zend引擎内实现的 在一个请求的开始设置一个"跳出"地址 然后在任何die()或exit()调用或在遇到任何关 键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址 尽管这个"跳出"进程能够简化程序执行的流程 但是 在绝大多数情况下 这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内存漏洞 现在 让我们来考虑下面这个简化版本的处理函数调用的引擎代码
复制代码代码如下: void call_function(const char *fname int fname_len TSRMLS_DC){ zend_function *fe; char *lcase_fname; /* PHP函数名是大小写不敏感的 *为了简化在函数表中对它们的定位 *所有函数名都隐含地翻译为小写的 */ lcase_fname = estrndup(fname fname_len); zend_str_tolower(lcase_fname fname_len); if (zend_hash_find(EG(function_table) lcase_fname fname_len(void **)fe) == FAILURE) { zend_execute(fe >op_array TSRMLS_CC); } else { php_error_docref(NULL TSRMLS_CC E_ERROR "Call to undefined function: %s()" fname); } efree(lcase_fname); }
当 执行到php_error_docref()这一行时 内部错误处理器就会明白该错误级别是critical 并相应地调用longjmp()来中断当前 程序流程并离开call_function()函数 甚至根本不会执行到efree(lcase_fname)这一行 你可能想把efree()代码行移 动到zend_error()代码行的上面 但是 调用这个call_function()例程的代码行会怎么样呢?fname本身很可能就是一个分配的 字符串 并且 在它被错误消息处理使用完之前 你根本不能释放它注意 这个php_error_docref()函数是trigger_error()函数的一个内部等价实现它的第一个参数是一个将被添加到docref的可选的文档引用 第三个参数可以是任何我们熟悉的E_*家族常量 用于指示错误的严重程度 第四个参数(最后一个)遵循printf()风格的格式化和变量参数列表式样四 Zend内存管理器在 上面的"跳出"请求期间解决内存泄漏的方案之一是 使用Zend内存管理(ZendMM)层 引擎的这一部分非常类似于操作系统的内存管理行为 分配内存 给调用程序 区别在于 它处于进程空间中非常低的位置而且是"请求感知"的 这样以来 当一个请求结束时 它能够执行与OS在一个进程终止时相同的行为 也就是说 它会隐式地释放所有的为该请求所占用的内存 图 展示了ZendMM与OS以及PHP进程之间的关系 图 Zend内存管理器代替系统调用来实现针对每一种请求的内存分配 除 了提供隐式内存清除功能之外 ZendMM还能够根据php ini中memory_limit的设置控制每一种内存请求的用法 如果一个脚本试图请求比 系统中可用内存更多的内存 或大于它每次应该请求的最大量 那么 ZendMM将自动地发出一个E_ERROR消息并且启动相应的"跳出"进程 这种方法 的一个额外优点在于 大多数内存分配调用的返回值并不需要检查 因为如果失败的话将会导致立即跳转到引擎的退出部分 把PHP内部代码和 OS的实际的内存管理层"钩"在一起的原理并不复杂 所有内部分配的内存都要使用一组特定的可选函数实现 例如 PHP代码不是使用malloc( ) 来分配一个 字节内存块而是使用了emalloc( ) 除了实现实际的内存分配任务外 ZendMM还会使用相应的绑定请求类型来标志该内存块 这 样以来 当一个请求"跳出"时 ZendMM可以隐式地释放它 经常情况下 内存一般都需要被分配比单个请求持续时间更长的一段时间 这 种类型的分配(因其在一次请求结束之后仍然存在而被称为"永久性分配") 可以使用传统型内存分配器来实现 因为这些分配并不会添加ZendMM使用的那 些额外的相应于每种请求的信息 然而有时 直到运行时刻才会确定是否一个特定的分配需要永久性分配 因此ZendMM导出了一组帮助宏 其行为类似于其它 的内存分配函数 但是使用最后一个额外参数来指示是否为永久性分配 如果你确实想实现一个永久性分配 那么这个参数应该被设置为 在这 种情况下 请求是通过传统型malloc()分配器家族进行传递的 然而 如果运行时刻逻辑认为这个块不需要永久性分配 那么 这个参数可以被设置为零 并且调用将会被调整到针对每种请求的内存分配器函数 例如 pemalloc(buffer_len )将映射到malloc(buffer_len) 而pemalloc(buffer_len )将被使用下列语句映射到emalloc(buffer_len) #define in Zend/zend_alloc h: #define pemalloc(size persistent) ((persistent)?malloc(size): emalloc(size)) 所有这些在ZendMM中提供的分配器函数都能够从下表中找到其更传统的对应实现 表格 展示了ZendMM支持下的每一个分配器函数以及它们的e/pe对应实现 表格 传统型相对于PHP特定的分配器
分配器函数 e/pe对应实现 void *malloc(size_t count); void *emalloc(size_t count);void *pemalloc(size_t count char persistent); void *calloc(size_t count); void *ecalloc(size_t count);void *pecalloc(size_t count char persistent); void *realloc(void *ptr size_t count); void *erealloc(void *ptr size_t count); void *perealloc(void *ptr size_t count char persistent); void *strdup(void *ptr); void *estrdup(void *ptr);void *pestrdup(void *ptr char persistent); void free(void *ptr); void efree(void *ptr); void pefree(void *ptr char persistent);
你可能会注意到 即使是pefree()函数也要求使用永久性标志 这是因为在调用pefree()时 它实际上并不知道是否ptr是一种永久性分 配 针对一个非永久性分配调用free()能够导致双倍的空间释放 而针对一种永久性分配调用efree()有可能会导致一个段错误 因为内存管理器会试 图查找并不存在的管理信息 因此 你的代码需要记住它分配的数据结构是否是永久性的 除了分配器函数核心部分外 还存在其它一些非常方便的ZendMM特定的函数 例如void *estrndup(void *ptr int len);该函数能够分配len个字节的内存并且从ptr处复制len个字节到最新分配的块 这个estrndup()函数的行为可以大致描述如下
复制代码代码如下: void *estrndup(void *ptr int len) { char *dst = emalloc(len); memcpy(dst ptr len); dst[len] = ; return dst; }
在 此 被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrndup()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如 printf()这样的希望以为NULL为结束符的函数 当使用estrndup()来复制非字符串数据时 最后一个字节实质上都浪费了 但其中的利明显 大于弊void *safe_emalloc(size_t size size_t count size_t addtl); void *safe_pemalloc(size_t size size_t count size_t addtl char persistent);这 些函数分配的内存空间最终大小是((size*count) addtl) 你可以会问 "为什么还要提供额外函数呢?为什么不使用一个 emalloc/pemalloc呢?"原因很简单 为了安全 尽管有时候可能性相当小 但是 正是这一"可能性相当小"的结果导致宿主平台的内存溢出 这可能会导致分配负数个数的字节空间 或更有甚者 会导致分配一个小于调用程序要求大小的字节空间 而safe_emalloc()能够避免这种类型的陷 井 通过检查整数溢出并且在发生这样的溢出时显式地预以结束注意 并不是所有的内存分配例程都有一个相应的p*对等实现 例如 不存在pestrndup() 并且在PHP 版本前也不存在safe_pemalloc()
五 引用计数慎重的内存分配与释放对于PHP(它是一种多请求进程)的长期性能有极其重大的影响 但是 这还仅是问题的一半 为了使一个每秒处理上千次点击的服务器高效地运行 每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作 请考虑下列PHP代码片断
复制代码代码如下: <?php $a = Hello World ; $b = $a; unset($a); ?>
在第一次调用之后 只有一个变量被创建 并且一个 字节的内存块指派给它以便存储字符串"Hello World" 还包括一个结尾处的NULL字符 现在 让我们来观察后面的两行 $b被置为与变量$a相同的值 然后变量$a被释放 如 果PHP因每次变量赋值都要复制变量内容的话 那么 对于上例中要复制的字符串还需要复制额外的 个字节 并且在数据复制期间还要进行另外的处理器加 载 这一行为乍看起来有点荒谬 因为当第三行代码出现时 原始变量被释放 从而使得整个数据复制显得完全不必要 其实 我们不妨再远一层考虑 让我们设想 当一个 MB大小的文件的内容被装载到两个变量中时会发生什么 这将会占用 MB的空间 此时 已经足够了 引擎会把那么多的时间和内存浪费在这 样一种无用的努力上吗? 你应该知道 PHP的设计者早已深谙此理 记住 在引擎中 变量名和它们的值实际上是两个不同的概念 值本身是一个无名的zval*存储体(在本例中 是一个字符串值) 它被通过zend_hash_add()赋给变量$a 如果两个变量名都指向同一个值 会发生什么呢?
复制代码代码如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") helloval sizeof(zval*) NULL); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") helloval sizeof(zval*) NULL); }
此 时 你可以实际地观察$a或$b 并且会看到它们都包含字符串"Hello World" 遗憾的是 接下来 你继续执行第三行代码"unset($a);" 此时 unset()并不知道$a变量指向的数据还被另一个变量所使 用 因此它只是盲目地释放掉该内存 任何随后的对变量$b的存取都将被分析为已经释放的内存空间并因此导致引擎崩溃 这个问题可以借助于 zval(它有好几种形式)的第四个成员refcount加以解决 当一个变量被首次创建并赋值时 它的refcount被初始化为 因为它被假定仅由 最初创建它时相应的变量所使用 当你的代码片断开始把helloval赋给$b时 它需要把refcount的值增加为 这样以来 现在该值被两个变量 所引用
复制代码代码如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") helloval sizeof(zval*) NULL); ZVAL_ADDREF(helloval); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") helloval sizeof(zval*) NULL); }
现在 当unset()删除原变量的$a相应的副本时 它就能够从refcount参数中看到 还有另外其php各数据类型占用空间他人对该数据感兴趣 因此 它应该只是减少refcount的计数值 然后不再管它
六 写复制(Copy on Write)通过refcounting来节约内存的确是不错的主意 但是 当你仅想改变其中一个变量的值时情况会如何呢?为此 请考虑下面的代码片断
复制代码代码如下: <?php $a = ; $b = $a; $b= ; ?>
通过上面的逻辑流程 你当然知道$a的值仍然等于 而$b的值最后将是 并且此时 你还知道 Zend在尽力节省内存 通过使$a和$b都引用相同的zval(见第二行代码) 那么 当执行到第三行并且必须改变$b变量的值时 会发生什么情况呢? 回答是 Zend要查看refcount的值 并且确保在它的值大于 时对之进行分离 在Zend引擎中 分离是破坏一个引用对的过程 正好与你刚才看到的过程相反
复制代码代码如下: zval *get_var_and_separate(char *varname int varname_len TSRMLS_DC) { zval **varval *varcopy; if (zend_hash_find(EG(active_symbol_table) varname varname_len(void**)varval) == FAILURE) { /* 变量根本并不存在 失败而导致退出*/ return NULL; } if ((*varval) >refcount < ) { /* varname是唯一的实际引用 *不需要进行分离 */ return *varval; } /* 否则 再复制一份zval*的值*/ MAKE_STD_ZVAL(varcopy); varcopy = *varval; /* 复制任何在zval*内的已分配的结构*/ zval_copy_ctor(varcopy); /*删除旧版本的varname *这将减少该过程中varval的refcount的值 */ zend_hash_del(EG(active_symbol_table) varname varname_len); /*初始化新创建的值的引用计数 并把它依附到 * varname变量 */ varcopy >refcount = ; varcopy >is_ref = ; zend_hash_add(EG(active_symbol_table) varname varname_lenvarcopy sizeof(zval*) NULL); /*返回新的zval* */ return varcopy; }
现在 既然引擎有一个仅为变量$b所拥有的zval*(引擎能知道这一点) 所以它能够把这个值转换成一个long型值并根据脚本的请求给它增加
七 写改变(change on write)引用计数概念的引入还导致了一个新的数据操作可能性 其形式从用户空间脚本管理器看来与"引用"有一定关系 请考虑下列的用户空间代码片断
复制代码代码如下: <?php $a = ; $b = $a; $b= ; ?>
在 上面的PHP代码中 你能看出$a的值现在为 尽管它一开始为 并且从未(直接)发生变化 之所以会发生这种情况是因为当引擎开始把$b的值增加 时 它注意到$b是一个对$a的引用并且认为"我可以改变该值而不必分离它 因为我想使所有的引用变量都能看到这一改变" 但是 引擎是如何 知道的呢?很简单 它只要查看一下zval结构的第四个和最后一个元素(is_ref)即可 这是一个简单的开/关位 它定义了该值是否实际上是一个用户 空间风格引用集的一部分 在前面的代码片断中 当执行第一行时 为$a创建的值得到一个refcount为 还有一个is_ref值为 因为它仅为一 个变量($a)所拥有并且没有其它变量对它产生写引用改变 在第二行 这个值的refcount元素被增加为 除了这次is_ref元素被置为 之外 (因为脚本中包含了一个""符号以指示是完全引用) 最后 在第三行 引擎再一次取出与变量$b相关的值并且检查是否有必要进行分离 这一次该值没有被分离 因为前面没有包括一个检查 下面是get_var_and_separate()函数中与refcount检查有关的部分代码
复制代码代码如下: if ((*varval) >is_ref || (*varval) >refcount < ) { /* varname是唯一的实际引用 * 或者它是对其它变量的一个完全引用 *任何一种方式 都没有进行分离 */ return *varval; }
这一次 尽管refcount为 却没有实现分离 因为这个值是一个完全引用 引擎能够自由地修改它而不必关心其它变量值的变化
八 分离问题尽管已经存在上面讨论到的复制和引用技术 但是还存在一些不能通过is_ref和refcount操作来解决的问题 请考虑下面这个PHP代码块
复制代码代码如下: <?php $a = ; $b = $a; $c = $a; ?>
在 此 你有一个需要与三个不同的变量相关联的值 其中 两个变量是使用了"change on write"完全引用方式 而第三个变量处于一种可分离 的"copy on write"(写复制)上下文中 如果仅使用is_ref和refcount来描述这种关系 有哪些值能够工作呢? 回答是 没有一个能工作 在这种情况下 这个值必须被复制到两个分离的zval*中 尽管两者都包含完全相同的数据(见图 )
图 引用时强制分离
同样 下列代码块将引起相同的冲突并且强迫该值分离出一个副本(见图 )
图 复制时强制分离
复制代码代码如下: <?php $a = ; $b = $a; $c = $a; ?> lishixinzhi/Article/program/PHP/201311/20951
php的问题我也遇到过,不过没理会!刚刚看到就去查了下为啥呢?还真找到了!转给你!
相信很多用了mysql很久的人,对这两个字段属性的概念还不是很清楚 , 一般会有以下疑问:
1、我字段类型是not null,为什么我可以插入空值
2、为毛not null的效率比null高
3、判断字段不为空的时候,到底要 select * from table where column'' 还是要用 select * from table where column is not null 呢 。
带着上面几个疑问,我们来深入研究一下null 和 not null 到底有什么不一样 。
首先,我们要搞清楚“空值” 和 “NULL” 的概念:
1、空值是不占用空间的
2、mysql中的NULL其实是占用空间的 , 下面是来自于MYSQL官方的解释
“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”
打个比方来说,你有一个杯子,空值代表杯子是真空的 , NULL代表杯子中装满了空气,虽然杯子看起来都是空的,但是区别是很大的 。
搞清楚“空值”和“NULL”的概念之后,问题基本就明了了,我们搞个例子测试一下:
CREATE TABLE`test` (
`col1` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`col2` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL
) ENGINE = MYISAM ;
插入数据:
INSERT INTO `test` VALUES (null,1);
mysql发生错误:
#1048 - Column 'col1' cannot be null
再来一条
INSERT INTO `test` VALUES ('',1);
成功插入 。
可见,NOT NULL 的字段是不能插入“NULL”的,只能插入“空值”,上面的问题1也就有答案了 。
对于问题2,上面我们已经说过了,NULL 其实并不是空值,而是要占用空间,所以mysql在进行比较的时候,NULL 会参与字段比较,所以对效率有一部分影响 。
而且对表索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多 。
我们再向test的表中插入几条数据:
INSERT INTO `test` VALUES ('', NULL);
INSERT INTO `test` VALUES ('1', '2');
现在表中数据:
现在根据需求,我要统计test表中col1不为空的所有数据,我是该用“ ''” 还是 “IS NOT NULL” 呢,让我们来看一下结果的区别 。
SELECT * FROM `test` WHERE col1 IS NOT NULL
SELECT * FROM `test` WHERE col1''
可以看到,结果迥然不同,所以我们一定要根据业务需求,搞清楚到底是要用那种搜索条件 。
---------------------------------
Mysql数据库是一个基于结构化数据的开源数据库 。SQL语句是MySQL数据库中核心语言 。不过在MySQL数据库中执行SQL语句,需要小心两个陷阱 。
陷阱一:空值不一定为空
空值是一个比较特殊的字段 。在MySQL数据库中,在不同的情形下,空值往往代表不同的含义 。这是MySQL数据库的一种特性 。如在普通的字段中(字符型的数据),空值就是表示空值 。但是如果将一个空值的数据插入到TimesTamp类型的字段中,空值就不一定为空 。此时为出现什么情况呢
我先创建了一个表 。在这个表中有两个字段:User_id(其数据类型是int)、Date(其数据类型是TimesTamp) 。现在往这个表中插入一条记录,其中往Date字段中插入的是一个NULL空值 。可是当我们查询时 , 其结果显示的却是插入记录的当前时间 。这是怎么一回事呢?其实这就是在MySQL数据库中执行SQL语句时经常会遇到的一个陷阱:空值不一定为空 。在操作时,明明插入的是一个空值的数据,但是最后查询得到的却不是一个空值 。
在MySQL数据库中,NULL对于一些特殊类型的列来说,其代表了一种特殊的含义,而不仅仅是一个空值 。对于这些特殊类型的列,各位读者主要是要记住两个 。一个就是笔者上面举的TimesTamp数据类型 。如果往这个数据类型的列中插入Null值,则其代表的就是系统的当前时间 。另外一个是具有auto_increment属性的列 。如果往这属性的列中插入Null值的话,则系统会插入一个正整数序列 。而如果在其他数据类型中 , 如字符型数据的列中插入Null的数据,则其插入的就是一个空值 。
陷阱二:空值不一定等于空字符
在MySQL中,空值(Null)与空字符(’’)相同吗?答案是否定的 。
在同一个数据库表中 , 同时插入一个Null值的数据和一个’’空字符的数据,然后利用Select语句进行查询 。显然其显示的结果是不相同的 。从这个结果中就可以看出,空值不等于空字符 。这就是在MySQL中执行SQL语句遇到的第二个陷阱 。在实际工作中,空值数据与空字符往往表示不同的含义 。数据库管理员可以根据实际的需要来进行选择 。如对于电话号码等字段,可以默认设置为空值(表示根本不知道对方的电话号码)或者设置为空字符(表示后来取消了这个号码)等等 。由于他们在数据库中会有不同的表现形式,所以数据库管理员需要区别对待 。笔者更加喜欢使用空值,而不是空字符 。这主要是因为针对空值这个数据类型有几个比较特殊的运算字符 。如果某个字段是空字符,数据库中是利用字段名称来代替 。相反 , 如果插入的是空值,则直接显示的是NULL 。这跟其他数据库的显示方式也是不同的 。
一是IS NULL 和IS NOT NULL关键字 。如果要判断某个字段是否含用空值的数据,需要使用特殊的关键字 。其中前者表示这个字段为空,后者表示这个字段为非空 。在Select语句的查询条件中这两个关键字非常的有用 。如需要查询所有电话号码为空的用户(需要他们补充电话号码信息),就可以在查询条件中加入is not null关键字 。
二是Count等统计函数 , 在空值上也有特殊的应用 。如现在需要统计用户信息表中有电话号码的用户数量,此时就可以使用count函数、同时将电话号码作为参数来使用 。因为在统计过程中,这个函数会自动忽略空值的数据 。此时统计出来的就是有电话号码的用户信息 。如果采用的是空字符的数据,则这个函数会将其统计进去 。统计刚才建立的两条记录时,系统统计的结果是1 , 而不是2 。可见系统自动将Null值的数据忽略掉了 。
判断NULL用is null或者 is not null 。sql语句里可以用ifnull函数来处理
判断空字符串‘’,要用 ='' 或者 '' 。sql语句里可以用if(col,col,0)处理,即:当col为true时(非null , 及非'')显示,否则打印0
PHP中变量和常量存储空间大小一样吗?变量和常量的存储空间一致 。
每个数据类型的各自大小不一样,有各自的范围
【php各数据类型占用空间 php占用内存过高】关于php各数据类型占用空间和php占用内存过高的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息 , 记得收藏关注本站 。

    推荐阅读