操作系统找不到已输入的环境选项解决方案

有时候修改环境变量的时候,不小心误删了一些环境变量,就会出现好多程序无法打开,显示操作系统找不到已输入的

环境选项。

例如这样:


你会去设置环境变量那看看哪个不见了,把它加回来,结果又出现这样的情况:



类似这种状况是误删了系统环境变量,系统环境变量中的两项可能有问题变量“windir”和“Path”,尤其可能已经误删除了或全部删除了。此时已经从资源管理器的“系统”打不开“高级系统设置”,需要从目录里打开,位于“C:\Windows\System32\SystemPropertiesAdvanced.exe”双击即可(直接在中运行就能找到了)。然后将下面的默认变量和值输进去就解决了:

用户变量

变量
Path %USERPROFILE%\AppData\Local\Microsoft\WindowsApps;
TEMP %USERPROFILE%\AppData\Local\Temp
TMP %USERPROFILE%\AppData\Local\Temp

系统变量

变量
ComSpec %SystemRoot%\system32\cmd.exe
NUMBER_OF_PROCESSORS 2
OS Windows_NT
PATH %SystemRoot%;%SystemRoot%\system32;%SystemRoot%\System32\wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\
PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE AMD64
PROCESSOR_IDENTIFIER Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
PROCESSOR_LEVEL 6
PROCESSOR_REVISION 3a09
PSModulePath %ProgramFiles%\WindowsPowerShell\Modules;%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules
TEMP %SystemRoot%\TEMP
TMP %SystemRoot%\TEMP
USERNAME SYSTEM
windir %SystemRoot%

具体步骤: 
1. 双击运行“C:\Windows\System32\SystemPropertiesAdvanced.exe” 
2. 点击“环境变量”按钮进入环境变量界面 
3. 在“用户变量”和“系统变量”中将上表缺少的默认变量和值输进去 
4. 完成编辑后点击“确认”保存

这里写图片描述

注意:如果“C:\Windows\System32\SystemPropertiesAdvanced.exe”程序双击无法运行,一些系统设置如注册表、音量设置、防火墙、高级系统设置等等都无法打开,或很多程序无法以管理员身份运行,又或者所有的系统文件夹在菜单栏都显示成这样: 
这里写图片描述 
那么就要重启电脑进入安全模式进行以上操作,因为此时所有操作都无法以管理员身份运行。很多人就因为这样而无法操作成功,以失败而告终。

Tips:

如何进入“安全模式”?

有两种版本的安全模式:安全模式和网络安全模式。虽然它们非常相似,但是网络安全模式包含网络驱动程序和服务,你将需要访问 Internet 和网络上的其他计算机。

一、通过“设置” 
1. 按键盘上的 Windows 徽标键 + I 可打开“设置”。如果不起作用,请选择屏幕左下角的“开始”按钮,然后选择“设置”。 
2. 依次选择“更新和安全” >“恢复”。 
3. 在“高级启动”下,选择“立即重启”。 
4. 在电脑重启到“选择一个选项”屏幕后,依次选择“疑难解答”>“高级选项”>“启动设置”>“重新启动”。 
5. 在电脑重新启动后,你将看到一列选项。选择 4 或 F4 以在“安全模式” 下启动电脑。或者,如果你需要使用 Internet,请选择“5”或“F5”进入“网络安全模式”。

二、通过登录屏幕 
1. 重新启动你的电脑。当你进入到登录屏幕后,在按住 Shift 键的同时依次选择“电源”“重新启动”。 
2. 在电脑重启到“选择一个选项”屏幕后,依次选择“疑难解答”>“高级选项”>“启动设置”>“重新启动”。 
3. 在电脑重新启动后,你将看到一列选项。选择“4”或“F4”以在“安全模式”下启动电脑。或者,如果你需要使用 Internet,请选择“5”或“F5”进入“网络安全模式”。

三、通过重启 
1. 重新启动你的电脑,狂按F8,选择安全模式进入

四、msconfig

1、鼠标点击Win10系统电脑桌面左下角的“开始”菜单,选择运行选项;
2、在打开的运行对话框里输入命令“msconfig”字符命令,点击确定键;
3、在打开的系统配置窗口,切换到“引导”标签,在引导选项下勾选安全引导(F),点击确定键;
勾选安全引导(F)
4、点击后,系统提示重新启动后,会进入安全模式;

五、有时候前面几种都还是进步了安全模式,那就可以试下这个暴力的方法,关机后,按下开机,启动界面时长按开机键强制关机,重复3次左右后再开机,就会进入修复模式,这时候就进入了类似方法二的 2 3步骤从而进入安全模式。


进入安全模式后,和之前的方法一样,打开C:\Windows\System32\SystemPropertiesAdvanced.exe, 添加环境变

windir=c:\windows,这样重启后,就能正常使用了。


  • 27
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
SQL Server 2008商业智能完美解决方案 2/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》: 利用Microsoft SQL Server 2008实现灵活的商业智能解决方案使用Microsoft 完善的BI工具构建B0解决方案的必备指南,使用SQLServer 2008设计、开发和部署更有效的数据集成、报表、分析解决方案所需的权威操作指南。不论是商业智能(B0)编程的新手还是老手,都会从中受益。通过专家团队的真实示例和高明见解,读者能够掌握构建商业智能解决方案的概念、工具和技术,从而真正提供客户所需的智能性商业价值。 《SQL Server 2008商业智能完美解决方案》研究如下内容: 管理开发生命周期,打造BI团队; 深入研究SQL Servet Analysis Services、Integration Services和 Reporting Services; 使用Business Intelligence Development Studio(BIDS); 编写对销售数据进行分级、排序和深化的查询; 开发提取、转换、加载(ETL)解决方案; 添加源代码控制系统; 通过加密和凭据保护部署的包; 用MDX和DMX查询设计器构建基于OLAP多维数据集和数据挖掘模 型的报表; 用NET代码建立并实现自定义对象; 在Microsoft Office Excel和Office SharePoint Server中查看报表。 微软公司US-SQL Analysis Services 首席开发经理Donaod Farmer倾力作序 内容提要 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》介绍如何使用Microsoft SQL Server 2008开发商业智能(BI)解决方案。《SQL Server 2008商业智能完美解决方案》共分为4部分。第一部分阐述了商业智能基础、可视化商业智能结果、构建有效的商业智能流程、商业智能解决方案的物理架构、面向架构师的OLAP逻辑设计概念;第二部分面向Analysis Services开发人员,详细介绍了如何使用BIDS以及BIDS的所有功能,提供了使用SSAS构建OLAP多维数据集和数据挖掘模型的指南;第三部分面向Integration Services开发人员,详细介绍如何使用SSIS开发ETL软件包,利用ETL包加载OLAP多维数据集和数据挖掘结构;第四部分详细介绍了SSRS的架构,以及Excel、Visio或Office SharePoint Server 2007作为BI客户端的实现。 《SQL Server 2008商业智能完美解决方案》结合专家团队提供的实际示例和丰富经验进行介绍,让读者能够直观轻松地掌握构建商业智能(BI)解决方案的概念、工具和技术,是一本不可多得的商业智能开发参考指南。无论是商业智能(BI)编程新手还是经验丰富的老手,都可从《SQL Server 2008商业智能完美解决方案》中获益。 目录 -------------------------------------------------------------------------------- 第一部分 面向商业决策者和架构师的商业智能 第1章 商业智能基础 3 1.1 商业智能和数据建模 3 1.2 OLTP和OLAP 4 1.2.1 联机事务处理 4 1.2.2 联机分析处理 6 1.3 常用BI术语 9 1.3.1 数据仓库 9 1.3.2 数据市场 10 1.3.3 多维数据集 11 1.3.4 决策支持系统 11 1.3.5 数据挖掘系统 11 1.3.6 提取、转换和加载系统 12 1.3.7 报表处理系统 12 1.3.8 关键绩效指标 12 1.4 Microsoft BI解决方案的核心组件 12 1.4.1 SQL Server 2008 Analysis Services 13 1.4.2 SQL Server 2008 Reporting Services 15 1.4.3 SQL Ser
缺乏道路限制数据 缺乏道路限制数据,导致规划路线,违反道路交规 结果不准 订单量增大时,排线结果常常不准,资源严重浪费 人为经验 依靠调度员排单排线,强依赖人为经验 超出时间窗 约束条件过多,导致无法满足网点要求(时间窗) 现状 城配企业接到订单,调度员依赖历史经验,考虑部分因素,制定调度计划 司机接收调度任务后,按照规划的路线进行行驶,事先未知道路限制和路况,经常违反道路交规 痛点 订单越多 效率越低 调度难度越高 传统调度的困局 物流智能调度解决方案全文共9页,当前为第1页。 用户需求 业务目标 痛点 某快消品B2B电商,北京近6万个零售终端点位,4个常温仓、1个冷链仓, 200多辆货车,约束条件复杂,每日配送需求动态变化 如何用最少的货车、跑最短的距离、用最快的时间、配送出最多的货 依靠调度师傅的个人经验,但这种运营规模早已超出人脑所能对比和计算的能力范围,人工规划远远达不到最优 典型的城配场景 车辆满载率最大是多少? 可用车辆及车型? 客户收货是否有时间窗? 明天下午3点的波次能否在6点前送完? 最大配送的站点数? 是否需要分区经营? ? 物流智能调度解决方案全文共9页,当前为第2页。 目标: 满⾜客户收货要求的前提下, 综合各种约束条件达到最优的调度方案 优化目标 成本最优 里程最优 时间最少 各项均衡 仓库要求 时间窗口 是否回仓 车辆组 多仓提货 车辆要求 最大行驶时间 最长行驶距离 重量体积配载 限行情况 通行限制 五限信息 通行证 避让区域 分时段限行 门店要求 配送时间窗口 停留时间 车辆要求 成本信息 固定出车成本 里程成本 时间成本 降本增效 节省运输车辆 降低里程数 节约调度时间 提高装配效率 我们的能力 —— 帮助传统物流企业破局 物流智能调度解决方案全文共9页,当前为第3页。 AI算法能力 百度物流地图 云计算 百度智能物流调度引擎 核心技术 物流智能调度解决方案全文共9页,当前为第4页。 算法优势 调度性能达到业界领先水平,拥有多项专利技术。节约10%-40%的运输成本 算力优势 依托百度智能云强大的可扩展算力快速生成千万级路网数据,支持多个高达数万点位的配送任务同时计算。 地图优势 依托强大的百度地图亿万级POI数据,支持全国五限信息避让导航。 场景丰富 支持时间窗口、满载率等20多种约束条件,满足多种配送场景的智能调度需求。 我们的优势 物流智能调度解决方案全文共9页,当前为第5页。 订单导入 批量订单一键导入,地址信息自动解析成经纬度,大幅节省调度员计算时间 规则设置 支持网点时间窗口、满载率、车辆种类、禁行限制等20多个约束条件限制 一键排单 系统一键排单,支持成本最优、总里程最短、总时间最短等多种优化目标 调度结果展示 地图展示调度结果,可一键发送给各个指派司机,可在地图上手动优化路径 开启白名单,运单数据导入系统,一键生成智能调度结果 使用方式 —— 1. SAAS化Console直接操作 物流智能调度解决方案全文共9页,当前为第6页。 使用方式 —— 2. API 集成 建议集成到贵司的业务系统中,使用更顺畅,下图是部分客户的集成效果界面。 物流智能调度解决方案全文共9页,当前为第7页。 典型案例 —— 货主 客户简介 中国烟草总公司安徽子公司,零售范围覆盖全省16个城市,全省共有26万销售网点,其中合肥市的销售网点高达3.2万个,自有配送车辆600多辆 项目需求 全市的销售网点,按照周一到周五分成五个区域,每一个配送区域要保证网点数量、送货量、配送总里程尽量均衡。 每个区域内,结合配送车辆的具体情况,将一个区域分成几十到上百条线路不等,每个配送车辆负责一个线路。 使用百度智能物流调度引擎前,每日排线需要2-3个调度师傅员,依靠排单经验,根据当地行政区域划分、路网情况,人工排出送货顺序,产生最终的配送计划。通常需要3个小时左右。 优化结果 我们采用成本最小和时间均衡策略,对客户的"配送分区、区内排线、线内优化"进行重新规划,与原有的依靠调度员经验规划的结果相比取得了显著效果 行驶里程降低 15% 运输成本降低 17% 调度时间降低 91% 物流智能调度解决方案全文共9页,当前为第8页。 典型案例 —— TMS厂商 汉得HTMS和百度ROS集成之后,简化了使用流程,提高易用性,客户可以零编程轻松调度;对销售而言,降低学习成本和售卖的难度。 集成前 集成后 客户需要分别使用汉得HTMS做运输管理,用百度ROS做智能调度,对运维人员的技术能力要求高,客户学习成本高,易用性差 客户可以直接使用汉得HTMS做运输管理和智能调度,百度的ROS的API变成汉得HTMS界面上的选项,可以零编程完成调度 客户需要将HTMS中的订单管理模块的订单导出,再按照百度ROS的格式导入进行排单,流程更复杂 将
SQL Server 2008商业智能完美解决方案 3/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》: 利用Microsoft SQL Server 2008实现灵活的商业智能解决方案使用Microsoft 完善的BI工具构建B0解决方案的必备指南,使用SQLServer 2008设计、开发和部署更有效的数据集成、报表、分析解决方案所需的权威操作指南。不论是商业智能(B0)编程的新手还是老手,都会从中受益。通过专家团队的真实示例和高明见解,读者能够掌握构建商业智能解决方案的概念、工具和技术,从而真正提供客户所需的智能性商业价值。 《SQL Server 2008商业智能完美解决方案》研究如下内容: 管理开发生命周期,打造BI团队; 深入研究SQL Servet Analysis Services、Integration Services和 Reporting Services; 使用Business Intelligence Development Studio(BIDS); 编写对销售数据进行分级、排序和深化的查询; 开发提取、转换、加载(ETL)解决方案; 添加源代码控制系统; 通过加密和凭据保护部署的包; 用MDX和DMX查询设计器构建基于OLAP多维数据集和数据挖掘模 型的报表; 用NET代码建立并实现自定义对象; 在Microsoft Office Excel和Office SharePoint Server中查看报表。 微软公司US-SQL Analysis Services 首席开发经理Donaod Farmer倾力作序 内容提要 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》介绍如何使用Microsoft SQL Server 2008开发商业智能(BI)解决方案。《SQL Server 2008商业智能完美解决方案》共分为4部分。第一部分阐述了商业智能基础、可视化商业智能结果、构建有效的商业智能流程、商业智能解决方案的物理架构、面向架构师的OLAP逻辑设计概念;第二部分面向Analysis Services开发人员,详细介绍了如何使用BIDS以及BIDS的所有功能,提供了使用SSAS构建OLAP多维数据集和数据挖掘模型的指南;第三部分面向Integration Services开发人员,详细介绍如何使用SSIS开发ETL软件包,利用ETL包加载OLAP多维数据集和数据挖掘结构;第四部分详细介绍了SSRS的架构,以及Excel、Visio或Office SharePoint Server 2007作为BI客户端的实现。 《SQL Server 2008商业智能完美解决方案》结合专家团队提供的实际示例和丰富经验进行介绍,让读者能够直观轻松地掌握构建商业智能(BI)解决方案的概念、工具和技术,是一本不可多得的商业智能开发参考指南。无论是商业智能(BI)编程新手还是经验丰富的老手,都可从《SQL Server 2008商业智能完美解决方案》中获益。 目录 -------------------------------------------------------------------------------- 第一部分 面向商业决策者和架构师的商业智能 第1章 商业智能基础 3 1.1 商业智能和数据建模 3 1.2 OLTP和OLAP 4 1.2.1 联机事务处理 4 1.2.2 联机分析处理 6 1.3 常用BI术语 9 1.3.1 数据仓库 9 1.3.2 数据市场 10 1.3.3 多维数据集 11 1.3.4 决策支持系统 11 1.3.5 数据挖掘系统 11 1.3.6 提取、转换和加载系统 12 1.3.7 报表处理系统 12 1.3.8 关键绩效指标 12 1.4 Microsoft BI解决方案的核心组件 12 1.4.1 SQL Server 2008 Analysis Services 13 1.4.2 SQL Server 2008 Reporting Services 15 1.4.3 SQL Server 2008 15 1.4.4 SQL Server 2008 Integration Services 15 1.5 Microsoft BI解决方案的可选组件 17 1.6 BI解决方案中使用的查询语言 18 1.6.1 MDX 18 1.6.2 DMX 19 1.6.3 XMLA 19 1.6.4 RDL 19 1.7 小结 19 第2章 商业智能结果可视化 21 2.1 将业务案例与BI解决方案对应起来 21 2.1.1 BI范围十大问题 22 2.1.2 BI解决方案的组成部分 23 2.2 从用户的角度理解商业智能 26 2.2.1 用Excel 2007演示BI的功能 28 2.2.2 通过Excel外接程序了解数据挖掘 35 2.2.3 使用Excel 2007查看数据挖掘结构 36 2.3 完整BI解决方案的元素 39 2.3.1 报表——确定谁将使用解决方案 39 2.3.2 ETL——实现解决方案的基础 40 2.3.3 数据挖掘——不可或缺 40 2.4 常见的业务挑战和BI解决方案 42 2.5 衡量BI解决方案的ROI 43 2.6 小结 45 第3章 构建有效的商业智能流程 46 3.1 BI项目的软件开发生命周期 46 3.1.1 Microsoft Solution Framework 47 3.1.2 Microsoft Solution Framework for Agile Software Development 48 3.1.3 将MSF用于BI项目 49 3.1.4 Microsoft Solution Framework的阶段和可交付成果 49 3.2 BI项目需要的技能 53 3.2.1 必备技能 54 3.2.2 可选技能 55 3.3 建立团队 57 3.4 小结 62 第4章 商业智能解决方案的物理架构 63 4.1 物理基础结构更改的规划 63 4.1.1 创建准确的基线调查 63 4.1.2 评估当前的服务级别协议 64 4.2 确定服务器的最优数量和最佳位置 65 4.2.1 物理服务器的考虑 67 4.2.2 逻辑服务器和服务的考虑 68 4.3 理解安全需求 70 4.4 备份和还原 78 4.4.1 备份SSAS 78 4.4.2 备份SSIS 79 4.4.3 备份SSRS 79 4.5 审核与合规 79 4.6 源代码控制 82 4.7 小结 83 第5章 面向架构的OLAP逻辑设计概念 84 5.1 设计基本的OLAP多维数据集 84 5.1.1 星形架构 85 5.1.2 反规范化 91 5.1.3 回到星形 91 5.1.4 其他设计技巧 96 5.1.5 雪花维度建模 97 5.1.6 维度建模补充 100 5.1.7 理解事实(度量)建模 105 5.1.8 BI建模的其他考虑 107 5.2 小结 108 第二部分 Microsoft SQL Server 2008 Analysis Services开发人员指南 第6章 理解SSMS和SQL Server Profiler中的SSAS 111 6.1 SQL Server Analysis Services的核心工具 111 6.1.1 基线服务配置 114 6.1.2 SSMS中的SSAS 115 6.1.3 如何查询SSAS对象 124 6.1.4 使用MDX模板 127 6.1.5 使用DMX模板 130 6.1.6 使用XMLA模板 131 6.1.7 SSMS小结 132 6.2 小结 132 第7章 用BIDS设计OLAP多维数据集 133 7.1 使用BIDS 133 7.2 在“解决方案资源管理器”中工作 135 7.2.1 Analysis Services中的数据源 137 7.2.2 数据源视图 139 7.2.3 Analysis Services中的角色 142 7.2.4 在Analysis Services对象上使用编译后的程序集 143 7.3 用BIDS构建OLAP多维数据集 144 7.4 理解维度 149 7.4.1 属性层次结构 150 7.4.2 属性关系 151 7.4.3 翻译 153 7.5 使用维度 154 7.5.1 度量值组 154 7.5.2 超越星形维度 157 7.6 构建第一个OLAP多维数据集 160 7.6.1 选择度量值组 160 7.6.2 增加维度 160 7.7 小结 164 第8章 优化多维数据集和维度 165 8.1 优化第一个OLAP多维数据集 165 8.1.1 翻译和透视 165 8.1.2 关键绩效指标 167 8.1.3 操作 171 8.1.4 计算(MDX脚本或计算成员) 176 8.2 使用多维数据集和维度属性 179 8.2.1 时间智能 181 8.2.2 SCOPE关键字 181 8.2.3 账户智能和一元运算符定义 182 8.2.4 其他向导选项 185 8.2.5 货币换算 185 8.3 高级多维数据集和维度属性 188 8.4 小结 189 第9章 处理多维数据集和维度 190 9.1 构建、处理和部署OLAP多维数据集 190 9.1.1 区分数据和元数据 191 9.1.2 在断开环境下工作 191 9.1.3 在联机环境下工作 193 9.1.4 理解聚合 193 9.2 分区 194 9.2.1 选择存储模式:MOLAP、HOLAP和ROLAP 196 9.2.2 OLTP表的分区 198 9.2.3 其他OLAP分区配置 199 9.3 实现聚合 199 9.3.1 聚合设计向导 200 9.3.2 基于使用情况的优化向导 202 9.3.3 SQL Server Profiler 203 9.3.4 聚合设计器:高级视图 204 9.4 用MOLAP、HOLAP或ROLAP实现高级存储 205 9.5 主动缓存 206 9.5.1 主动缓存的通知设置 208 9.5.2 主动缓存调优 208 9.5.3 ROLAP维度 209 9.5.4 链接 210 9.5.5 写回 210 9.6 多维数据集和维度处理选项 212 9.7 小结 215 第10章 MDX简介 216 10.1 MDX的重要性 216 10.2 编写第一个MDX查询 217 10.2.1 MDX对象名称 218 10.2.2 MDX语法的其他元素 218 10.3 MDX核心函数 220 10.4 筛选MDX结果集 226 10.5 计算成员和命名集合 228 10.6 TopCount函数 230 10.7 Rank函数和组合 232 10.8 Head和Tail函数 235 10.9 MDX的层次结构函数 236 10.10 日期函数 239 10.10.1 结合使用聚合和日期函数 242 10.10.2 关于查询优化 243 10.11 小结 244 第11章 高级MDX 245 11.1 查询维度属性 245 11.2 从季节角度查看日期维度和MDX 248 11.3 创建持久计算成员 249 11.3.1 在BIDS中创建持久计算成员 249 11.3.2 用MDX脚本创建计算成员 250 11.4 使用IIf 251 11.5 关于命名集 252 11.6 关于脚本 255 11.7 理解SOLVE_ORDER 257 11.8 创建关键绩效指标 258 11.8.1 编程创建KPI 261 11.8.2 KPI的其他提示 262 11.9 在SSRS和PerformancePoint Server上使用MDX 262 11.9.1 在SSRS 2008中使用MDX 262 11.9.2 在PerformancePoint Server 2007上使用MDX 264 11.10 小结 267 第12章 理解数据挖掘结构 268 12.1 审核业务场景 268 12.2 使用BIDS数据挖掘界面 271 12.2.1 理解数据类型和内容类型 272 12.2.2 设置高级数据属性 274 12.2.3 选择数据挖掘模型 275 12.2.4 选择最合适的挖掘模型查看器 278 12.2.5 挖掘准确性图表和预测 281 12.3 数据挖掘算法 284 12.3.1 Microsoft朴素贝叶斯 284 12.3.2 Microsoft决策树算法 288 12.3.3 Microsoft线性回归算法 290 12.3.4 Microsoft时间序列算法 290 12.3.5 Microsoft聚类算法 292 12.3.6 Microsoft序列聚类 294 12.3.7 Microsoft关联算法 295 12.3.8 Microsoft神经网络算法 299 12.3.9 Microsoft逻辑回归 300 12.4 数据挖掘的艺术 301 12.5 小结 301 第13章 实现数据挖掘结构 302 13.1 实现CRISP-DM生命周期模型 302 13.2 用BIDS构建数据挖掘结构 303 13.3 用BIDS增加数据挖掘模型 305 13.4 处理挖掘模型 308 13.5 验证挖掘模型 310 13.5.1 提升图 310 13.5.2 利润图 312 13.5.3 分类矩阵 313 13.5.4 交叉验证 315 13.6 数据挖掘预测查询 316 13.6.1 DMX预测查询 318 13.6.2 DMX预测函数 320 13.7 数据挖掘和Integration Services 322 13.8 数据挖掘对象的处理 324 13.9 数据挖掘客户端 326 13.10 小结 326 第三部分 Microsoft SQL Server 2008 Integration Services开发人员指南 第14章 Microsoft SQL Server 2008 Integration Services的架构组件 329 14.1 Integration Services架构概述 329 14.2 Integration Services包 331 14.3 Integration Services对象模型和组件 334 14.3.1 控制流 335 14.3.2 数据流 335 14.3.3 变量 337 14.3.4 表达式 338 14.3.5 连接管理器 339 14.3.6 事件处理程序和错误处理 340 14.4 Integration Services运行时 341 14.5 Integration Services数据流引擎 342 14.5.1 数据流缓冲区 342 14.5.2 同步数据流输出 346 14.5.3 异步数据流输出 346 14.6 日志提供程序 346 14.7 部署Integration Services包 347 14.7.1 包配置 347 14.7.2 包部署选项 348 14.8 小结 348 第15章 用Business Intelligence Development Studio创建Microsoft SQL Server 2008 Integration Services包 349 15.1 Visual Studio 2008中的Integration Services 349 15.1.1 使用Integration Services项目模板创建新SSIS项目 350 15.1.2 在“解决方案资源管理器”中查看SSIS项目 351 15.1.3 使用SSIS包设计器 352 15.1.4 使用SSIS工具箱 353 15.1.5 SSIS菜单选项 354 15.2 连接管理器 355 15.2.1 标准数据库连接管理器 355 15.2.2 其他类型的连接管理器 356 15.3 控制流 356 15.3.1 控制流任务 358 15.3.2 控制流容器 360 15.3.3 优先约束 360 15.4 数据流 362 15.4.1 数据流源组件 363 15.4.2 目标组件 364 15.4.3 转换组件 364 15.4.4 Integration Services数据查看器 366 15.5 变量 367 15.5.1 “变量”窗口 367 15.5.2 变量属性 368 15.5.3 系统变量 369 15.6 表达式 369 15.7 小结 371 第16章 Microsoft SQL Server 2008 Integration Services的高级功能 372 16.1 Integration Services中的错误处理 372 16.2 SSIS中的事件、日志、调试和事务 373 16.3 日志记录和事件 374 16.4 调试Integration Services包 377 16.5 检查点和事务 378 16.6 设计Integration Services包的最佳实践 380 16.7 数据事件探查 381 16.8 小结 384 第17章 商业智能解决方案中的Microsoft SQL Server 2008 Integration Services包 385 17.1 商业智能的ETL 385 17.2 加载OLAP多维数据集 385 17.2.1 使用Integration Services检测数据质量 386 17.2.2 转换源数据 388 17.2.3 使用中间服务器 388 17.2.4 数据沿袭 392 17.3 转移到星形架构加载 393 17.3.1 加载维度表 393 17.3.2 加载事实数据表 394 17.4 更新 397 17.4.1 事实数据表更新 398 17.4.2 维度表更新 398 17.5 数据挖掘的ETL 399 17.5.1 初始加载 399 17.5.2 模型定型 400 17.5.3 数据挖掘查询 401 17.6 小结 402 第18章 在Microsoft SQL Server 2008 Integration Services中部署和管理解决方案 403 18.1 Integration Services中的解决方案和项目结构 403 18.2 源代码控制 403 18.3 部署问题 407 18.3.1 包配置 409 18.3.2 复制文件部署 411 18.3.3 BIDS部署 412 18.3.4 使用部署实用工具部署 414 18.4 SQL Server代理和集成服务 416 18.4.1 SSIS包安全性介绍 416 18.4.2 处理敏感数据和代理执行账户 419 18.4.3 安全性:两个规则 420 18.5 SSIS服务 420 18.6 小结 421 第19章 扩展和集成SQL Server 2008 Integration Services 422 19.1 SSIS脚本介绍 422 19.2 Visual Studio Tools for Applications 423 19.3 脚本任务 423 19.3.1 Dts对象 425 19.3.2 调试脚本任务 426 19.4 脚本组件 426 19.4.1 ComponentMetaData属性 431 19.4.2 源、转换和目标 432 19.4.3 调试脚本组件 436 19.5 自定义SSIS任务和组件开发概述 436 19.5.1 控制流任务 439 19.5.2 数据流组件 440 19.5.3 其他组件 440 19.6 自定义应用程序中的SSIS集成概述 442 19.7 小结 444 第四部分 Microsoft SQL Server Reporting Services及商业智能的其他客户端界面 第20章 用SQL Server 2008 Reporting Services创建报表 447 20.1 了解Reporting Services的架构 447 20.2 安装和配置Reporting Services 449 20.2.1 HTTP侦听器 451 20.2.2 报表管理器 451 20.2.3 报表服务器Web服务 451 20.2.4 身份验证 452 20.2.5 后台处理(作业管理器) 453 20.3 使用BIDS创建报表 453 20.3.1 其他类型的报表 460 20.3.2 报表示例 460 20.4 部署报表 461 20.5 小结 462 第21章 创建SQL Server 2008 Reporting Services报表 463 21.1 将查询设计器用于Analysis Services 463 21.1.1 MDX查询设计器 464 21.1.2 在查询中设置参数 466 21.1.3 DMX查询设计器 467 21.1.4 在BIDS中使用报表设计器 469 21.2 理解报表项 471 21.2.1 列表和矩形报表项 471 21.2.2 Tablix数据区域 472 21.3 使用报表生成器 474 21.4 小结 477 第22章 高级SQL Sever 2008 Reporting Services 478 22.1 向SSRS报表添加自定义代码 478 22.2 在Word或Excel 2007中查看报表 480 22.3 URL访问 480 22.4 嵌入自定义ReportViewer控件 481 22.5 关于报表参数 485 22.6 关于安全凭据 485 22.7 关于SOAP API 486 22.8 部署——可伸缩性和安全性 490 22.8.1 性能和可伸缩性 490 22.8.2 高级内存管理 491 22.8.3 扩展 492 22.9 管理脚本 493 22.10 小结 494 第23章 用Microsoft Excel 2007作为OLAP多维数据集客户端 495 23.1 使用数据连接向导 495 23.2 使用“导入数据”对话框 497 23.3 理解“数据透视表”界面 497 23.4 创建示例数据透视表 499 23.5 脱机OLAP 501 23.6 Excel OLAP函数 502 23.7 扩展Excel 502 23.8 小结 503 第24章 用Microsoft Office 2007作为数据挖掘客户端 504 24.1 安装数据挖掘外接程序 504 24.2 数据挖掘和Excel 2007的集成 505 24.2.1 使用表分析工具组 506 24.2.2 在Excel 2007中使用“数据挖掘”选项卡 514 24.2.3 “管理”和“模型用法” 515 24.2.4 “数据准备”组 517 24.2.5 “数据建模”组 519 24.2.6 “准确性和验证”组 522 24.3 Visio 2007中的数据挖掘集成 523 24.4 客户端可视化 527 24.5 云形图中的数据挖掘 528 24.6 小结 528 第25章 SQL Server商业智能和Microsoft Office SharePoint Server 2007 529 25.1 Excel Services 529 25.1.1 Excel Services的基本架构 530 25.1.2 Excel工作表的永久性 531 25.1.3 Excel Services工作表的介绍性示例 531 25.1.4 发布参数化Excel工作表 533 25.1.5 Excel Services:Web Services API 535 25.1.6 实际的Excel Services示例 536 25.2 SQL Server Reporting Services与Office SharePoint Server 2007 538 25.2.1 使用Office SharePoint Server 2007配置SQL Server Reporting Services 539 25.2.2 创建并部署一个报表 539 25.2.3 在Office SharePoint Server 2007中使用报表:本机模式 541 25.2.4 在Office SharePoint Server 2007中使用报表:SharePoint集成模式 542 25.2.5 使用报告中心模板 544 25.3 PerformancePoint Server 545 25.4 小结 545 作者介绍 -------------------------------------------------------------------------------- 作者:(美国)兰吉特(Lynn Langit) (美国)Kevin S.Goff (美国)Davide Mauri 等 译者:张猛 杨越 朗亚妹 等 Lynn Langit,MicrosoftMSDN团队的一位开发人员讲师。在加入微软公司之前,Lynn创办了一家提供B0解决方案的开发公司,并担任首席架构师。她拥有很多Microsoft认证,包括MCITP、MCSD、MCDBA和MCT。 Kevin S,Goff,Microsoft MVP和培训师,还是Microsoft金牌认证合作伙伴项目的BI实践负责人。拥有MCP、MCAD、MCDBA和MCT认证。 Davide Mauri,Microsoft MVP,他从65版起就一直使用SQL Server。Sahil Malik咨询师和培训师,多年的Microsoft MVP和INETA发言人。 John Welch ,crosoft MVP,一家专攻BI解决方案的咨询公司的首席架构师。 -------------------------------------------------------------------------------- 9.5.4 链接 在准备处理多维数据集的时候,还有另外两个配置选项和功能需要考虑,即链接对象和写回.我们还要研究有关错误处理的设置(在“多维数据集和维度处理选项”一节),因为根据业务需求不同,这些配置也很重要,而且它们的配置值会影响多维数据集的处理时间。我们先从链接对象开始。 链接对象是需要与当前操作的SSAS数据库相关联的、来自其他SSAS数据库(Analysis Services 2008或Analysis Services 2005)的SSAS对象,如度量值组或维度。链接对象也可以包含KPI、操作和计算。链接对象选项可以用来克服SSAS 2008一个多维数据集只能基于一个数据源视图的局限性。它还可以实现某种伸缩性,因为可以使用多个服务器提供数据查询。 SSAS中使用链接对象的功能默认是禁用的。如果想使用这个选项,需要在SSMS中启用它,需将SSMS连接到SSAS,在SSAS服务器实例上单击右键,选择“属性”选项,然后启用链接。
SQL Server 2008商业智能完美解决方案 3/3 SQL Server 2008 2010 商业智能完美解决方案 作者:兰吉特(Lynn Langit) 出版社:人民邮电出版社; 第1版 (2010年8月1日) ISBN:7115231117, 9787115231116 页码:545 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》: 利用Microsoft SQL Server 2008实现灵活的商业智能解决方案使用Microsoft 完善的BI工具构建B0解决方案的必备指南,使用SQLServer 2008设计、开发和部署更有效的数据集成、报表、分析解决方案所需的权威操作指南。不论是商业智能(B0)编程的新手还是老手,都会从中受益。通过专家团队的真实示例和高明见解,读者能够掌握构建商业智能解决方案的概念、工具和技术,从而真正提供客户所需的智能性商业价值。 《SQL Server 2008商业智能完美解决方案》研究如下内容: 管理开发生命周期,打造BI团队; 深入研究SQL Servet Analysis Services、Integration Services和 Reporting Services; 使用Business Intelligence Development Studio(BIDS); 编写对销售数据进行分级、排序和深化的查询; 开发提取、转换、加载(ETL)解决方案; 添加源代码控制系统; 通过加密和凭据保护部署的包; 用MDX和DMX查询设计器构建基于OLAP多维数据集和数据挖掘模 型的报表; 用NET代码建立并实现自定义对象; 在Microsoft Office Excel和Office SharePoint Server中查看报表。 微软公司US-SQL Analysis Services 首席开发经理Donaod Farmer倾力作序 内容提要 -------------------------------------------------------------------------------- 《SQL Server 2008商业智能完美解决方案》介绍如何使用Microsoft SQL Server 2008开发商业智能(BI)解决方案。《SQL Server 2008商业智能完美解决方案》共分为4部分。第一部分阐述了商业智能基础、可视化商业智能结果、构建有效的商业智能流程、商业智能解决方案的物理架构、面向架构师的OLAP逻辑设计概念;第二部分面向Analysis Services开发人员,详细介绍了如何使用BIDS以及BIDS的所有功能,提供了使用SSAS构建OLAP多维数据集和数据挖掘模型的指南;第三部分面向Integration Services开发人员,详细介绍如何使用SSIS开发ETL软件包,利用ETL包加载OLAP多维数据集和数据挖掘结构;第四部分详细介绍了SSRS的架构,以及Excel、Visio或Office SharePoint Server 2007作为BI客户端的实现。 《SQL Server 2008商业智能完美解决方案》结合专家团队提供的实际示例和丰富经验进行介绍,让读者能够直观轻松地掌握构建商业智能(BI)解决方案的概念、工具和技术,是一本不可多得的商业智能开发参考指南。无论是商业智能(BI)编程新手还是经验丰富的老手,都可从《SQL Server 2008商业智能完美解决方案》中获益。 目录 -------------------------------------------------------------------------------- 第一部分 面向商业决策者和架构师的商业智能 第1章 商业智能基础 3 1.1 商业智能和数据建模 3 1.2 OLTP和OLAP 4 1.2.1 联机事务处理 4 1.2.2 联机分析处理 6 1.3 常用BI术语 9 1.3.1 数据仓库 9 1.3.2 数据市场 10 1.3.3 多维数据集 11 1.3.4 决策支持系统 11 1.3.5 数据挖掘系统 11 1.3.6 提取、转换和加载系统 12 1.3.7 报表处理系统 12 1.3.8 关键绩效指标 12 1.4 Microsoft BI解决方案的核心组件 12 1.4.1 SQL Server 2008 Analysis Services 13 1.4.2 SQL
文将对 Linux™ 程序员可以使用的内存管理技术进行概述,虽然关注的重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半手工地管理内存,以及如何使用垃圾收集自动管理内存。 为什么必须管理内存 内存管理是计算机编程最为基本的领域之一。在很多脚本语言中,您不必担心内存是如何管理的,这并不能使得内存管理的重要性有一点点降低。对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上进行汇编语言编程的时代,那时内存管理还不是个大问题。您实际上在运行整个系统。系统有多少内存,您就有多少内存。您甚至不必费心思去弄明白它有多少内存,因为每一台机器的内存数量都相同。所以,如果内存需要非常固定,那么您只需要选择一个内存范围并使用它即可。 不过,即使是在这样一个简单的计算机中,您也会有问题,尤其是当您不知道程序的每个部分将需要多少内存时。如果您的空间有限,而内存需求是变化的,那么您需要一些方法来满足这些需求: 确定您是否有足够的内存来处理数据。 从可用的内存中获取一部分内存。 向可用内存池(pool)中返回部分内存,以使其可以由程序的其他部分或者其他程序使用。 实现这些需求的程序库称为 分配程序(allocators),因为它们负责分配和回收内存。程序的动态性越强,内存管理就越重要,您的内存分配程序的选择也就更重要。让我们来了解可用于内存管理的不同方法,它们的好处与不足,以及它们最适用的情形。 回页首 C 风格的内存分配程序 C 编程语言提供了两个函数来满足我们的三个需求: malloc:该函数分配给定的字节数,并返回一个指向它们的指针。如果没有足够的可用内存,那么它返回一个空指针。 free:该函数获得指向由 malloc 分配的内存片段的指针,并将其释放,以便以后的程序或操作系统使用(实际上,一些 malloc 实现只能将内存归还给程序,而无法将内存归还给操作系统)。 物理内存和虚拟内存 要理解内存在程序中是如何分配的,首先需要理解如何将内存从操作系统分配给程序。计算机上的每一个进程都认为自己可以访问所有的物理内存。显然,由于同时在运行多个程序,所以每个进程不可能拥有全部内存。实际上,这些进程使用的是 虚拟内存。 只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM 中。实际上,它甚至可以不在 RAM 中 —— 如果物理 RAM 已经满了,它甚至可能已经被转移到硬盘上!由于这类地址不必反映内存所在的物理位置,所以它们被称为虚拟内存。操作系统维持着一个虚拟地址到物理地址的转换的表,以便计算机硬件可以正确地响应地址请求。并且,如果地址在硬盘上而不是在 RAM 中,那么操作系统将暂时停止您的进程,将其他内存转存到硬盘中,从硬盘上加载被请求的内存,然后再重新启动您的进程。这样,每个进程都获得了自己可以使用的地址空间,可以访问比您物理上安装的内存更多的内存。 在 32-位 x86 系统上,每一个进程可以访问 4 GB 内存。现在,大部分人的系统上并没有 4 GB 内存,即使您将 swap 也算上, 每个进程所使用的内存也肯定少于 4 GB。因此,当加载一个进程时,它会得到一个取决于某个称为 系统中断点(system break)的特定地址的初始内存分配。该地址之后是未被映射的内存 —— 用于在 RAM 或者硬盘中没有分配相应物理位置的内存。因此,如果一个进程运行超出了它初始分配的内存,那么它必须请求操作系统“映射进来(map in)”更多的内存。(映射是一个表示一一对应关系的数学术语 —— 当内存的虚拟地址有一个对应的物理地址来存储内存内容时,该内存将被映射。) 基于 UNIX 的系统有两个可映射到附加内存中的基本系统调用: brk: brk() 是一个非常简单的系统调用。还记得系统中断点吗?该位置是进程映射的内存边界。 brk() 只是简单地将这个位置向前或者向后移动,就可以向进程添加内存或者从进程取走内存。 mmap: mmap(),或者说是“内存映像”,类似于 brk(),但是更为灵活。首先,它可以映射任何位置的内存,而不单单只局限于进程。其次,它不仅可以将虚拟地址映射到物理的 RAM 或者 swap,它还可以将它们映射到文件和文件位置,这样,读写内存将对文件中的数据进行读写。不过,在这里,我们只关心 mmap 向进程添加被映射的内存的能力。 munmap() 所做的事情与 mmap() 相反。 如您所见, brk() 或者 mmap() 都可以用来向我们的进程添加额外的虚拟内存。在我们的例子中将使用 brk(),因为它更简单,更通用。 实现一个简单的分配程序 如果您曾经编写过很多 C 程序,那么您可能曾多次使用过 malloc() 和 free()。不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。 要试着运行这些示例,需要先 复制本代码清单,并将其粘贴到一个名为 malloc.c 的文件中。接下来,我将一次一个部分地对该清单进行解释。 在大部分操作系统中,内存分配由以下两个简单的函数来处理: void *malloc(long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。 void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。 malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量: 清单 1. 我们的简单分配程序的全局变量 int has_initialized = 0; void *managed_memory_start; void *last_valid_address; 如前所述,被映射的内存的边界(最后一个有效地址)常被称为系统中断点或者 当前中断点。在很多 UNIX® 系统中,为了指出当前系统中断点,必须使用 sbrk(0) 函数。 sbrk 根据参数中给出的字节数移动当前系统中断点,然后返回新的系统中断点。使用参数 0 只是返回当前中断点。这里是我们的 malloc 初始化代码,它将到当前中断点并初始化我们的变量: 清单 2. 分配程序初始化函数 /* Include the sbrk function */ #include void malloc_init() { /* grab the last valid address from the OS */ last_valid_address = sbrk(0); /* we don't have any memory to manage yet, so *just set the beginning to be last_valid_address */ managed_memory_start = last_valid_address; /* Okay, we're initialized and ready to go */ has_initialized = 1; } 现在,为了完全地管理内存,我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构: 清单 3. 内存控制块结构定义 struct mem_control_block { int is_available; int size; }; 现在,您可能会认为当程序调用 malloc 时这会引发问题 —— 它们如何知道这个结构?答案是它们不必知道;在返回指针之前,我们会将其移动到这个结构之后,把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次到这个结构。 在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码: 清单 4. 解除分配函数 void free(void *firstbyte) { struct mem_control_block *mcb; /* Backup from the given pointer to find the * mem_control_block */ mcb = firstbyte - sizeof(struct mem_control_block); /* Mark the block as being available */ mcb->is_available = 1; /* That's It! We're done. */ return; } 如您所见,在这个分配程序中,内存的释放使用了一个非常简单的机制,在固定时间内完成内存释放。分配内存稍微困难一些。以下是该算法的略述: 清单 5. 主分配程序的伪代码 1. If our allocator has not been initialized, initialize it. 2. Add sizeof(struct mem_control_block) to the size requested. 3. start at managed_memory_start. 4. Are we at last_valid address? 5. If we are: A. We didn't find any existing space that was large enough -- ask the operating system for more and return that. 6. Otherwise: A. Is the current space available (check is_available from the mem_control_block)? B. If it is: i) Is it large enough (check "size" from the mem_control_block)? ii) If so: a. Mark it as unavailable b. Move past mem_control_block and return the pointer iii) Otherwise: a. Move forward "size" bytes b. Go back go step 4 C. Otherwise: i) Move forward "size" bytes ii) Go back to step 4 我们主要使用连接的指针遍历内存来寻开放的内存块。这里是代码: 清单 6. 主分配程序 void *malloc(long numbytes) { /* Holds where we are looking in memory */ void *current_location; /* This is the same as current_location, but cast to a * memory_control_block */ struct mem_control_block *current_location_mcb; /* This is the memory location we will return. It will * be set to 0 until we find something suitable */ void *memory_location; /* Initialize if we haven't already done so */ if(! has_initialized) { malloc_init(); } /* The memory we search for has to include the memory * control block, but the users of malloc don't need * to know this, so we'll just add it in for them. */ numbytes = numbytes + sizeof(struct mem_control_block); /* Set memory_location to 0 until we find a suitable * location */ memory_location = 0; /* Begin searching at the start of managed memory */ current_location = managed_memory_start; /* Keep going until we have searched all allocated space */ while(current_location != last_valid_address) { /* current_location and current_location_mcb point * to the same address. However, current_location_mcb * is of the correct type, so we can use it as a struct. * current_location is a void pointer so we can use it * to calculate addresses. */ current_location_mcb = (struct mem_control_block *)current_location; if(current_location_mcb->is_available) { if(current_location_mcb->size >= numbytes) { /* Woohoo! We've found an open, * appropriately-size location. */ /* It is no longer available */ current_location_mcb->is_available = 0; /* We own it */ memory_location = current_location; /* Leave the loop */ break; } } /* If we made it here, it's because the Current memory * block not suitable; move to the next one */ current_location = current_location + current_location_mcb->size; } /* If we still don't have a valid location, we'll * have to ask the operating system for more memory */ if(! memory_location) { /* Move the program break numbytes further */ sbrk(numbytes); /* The new memory will be where the last valid * address left off */ memory_location = last_valid_address; /* We'll move the last valid address forward * numbytes */ last_valid_address = last_valid_address + numbytes; /* We need to initialize the mem_control_block */ current_location_mcb = memory_location; current_location_mcb->is_available = 0; current_location_mcb->size = numbytes; } /* Now, no matter what (well, except for error conditions), * memory_location has the address of the memory, including * the mem_control_block */ /* Move the pointer past the mem_control_block */ memory_location = memory_location + sizeof(struct mem_control_block); /* Return the pointer */ return memory_location; } 这就是我们的内存管理器。现在,我们只需要构建它,并在程序中使用它即可。 运行下面的命令来构建 malloc 兼容的分配程序(实际上,我们忽略了 realloc() 等一些函数,不过, malloc() 和 free() 才是最主要的函数): 清单 7. 编译分配程序 gcc -shared -fpic malloc.c -o malloc.so 该程序将生成一个名为 malloc.so 的文件,它是一个包含有我们的代码的共享库。 在 UNIX 系统中,现在您可以用您的分配程序来取代系统的 malloc(),做法如下: 清单 8. 替换您的标准的 malloc LD_PRELOAD=/path/to/malloc.so export LD_PRELOAD LD_PRELOAD 环境变量使动态链接器在加载任何可执行程序之前,先加载给定的共享库的符号。它还为特定库中的符号赋予优先权。因此,从现在起,该会话中的任何应用程序都将使用我们的 malloc(),而不是只有系统的应用程序能够使用。有一些应用程序不使用 malloc(),不过它们是例外。其他使用 realloc() 等其他内存管理函数的应用程序,或者错误地假定 malloc() 内部行为的那些应用程序,很可能会崩溃。ash shell 似乎可以使用我们的新 malloc() 很好地工作。 如果您想确保 malloc() 正在被使用,那么您应该通过向函数的入口点添加 write() 调用来进行测试。 我们的内存管理器在很多方面都还存在欠缺,但它可以有效地展示内存管理需要做什么事情。它的某些缺点包括: 由于它对系统中断点(一个全局变量)进行操作,所以它不能与其他分配程序或者 mmap 一起使用。 当分配内存时,在最坏的情形下,它将不得不遍历 全部进程内存;其中可能包括位于硬盘上的很多内存,这意味着操作系统将不得不花时间去向硬盘移入数据和从硬盘中移出数据。 没有很好的内存不足处理方案( malloc 只假定内存分配是成功的)。 它没有实现很多其他的内存函数,比如 realloc()。 由于 sbrk() 可能会交回比我们请求的更多的内存,所以在堆(heap)的末端会遗漏一些内存。 虽然 is_available 标记只包含一位信息,但它要使用完整的 4-字节 的字。 分配程序不是线程安全的。 分配程序不能将空闲空间拼合为更大的内存块。 分配程序的过于简单的匹配算法会导致产生很多潜在的内存碎片。 我确信还有很多其他问题。这就是为什么它只是一个例子! 其他 malloc 实现 malloc() 的实现有很多,这些实现各有优点与缺点。在设计一个分配程序时,要面临许多需要折衷的选择,其中包括: 分配的速度。 回收的速度。 有线程的环境的行为。 内存将要被用光时的行为。 局部缓存。 簿记(Bookkeeping)内存开销。 虚拟内存环境中的行为。 小的或者大的对象。 实时保证。 每一个实现都有其自身的优缺点集合。在我们的简单的分配程序中,分配非常慢,而回收非常快。另外,由于它在使用虚拟内存系统方面较差,所以它最适于处理大的对象。 还有其他许多分配程序可以使用。其中包括: Doug Lea Malloc:Doug Lea Malloc 实际上是完整的一组分配程序,其中包括 Doug Lea 的原始分配程序,GNU libc 分配程序和 ptmalloc。 Doug Lea 的分配程序有着与我们的版本非常类似的基本结构,但是它加入了索引,这使得搜索速度更快,并且可以将多个没有被使用的块组合为一个大的块。它还支持缓存,以便更快地再次使用最近释放的内存。 ptmalloc 是 Doug Lea Malloc 的一个扩展版本,支持多线程。在本文后面的 参考资料部分中,有一篇描述 Doug Lea 的 Malloc 实现的文章。 BSD Malloc:BSD Malloc 是随 4.2 BSD 发行的实现,包含在 FreeBSD 之中,这个分配程序可以从预先确实大小的对象构成的池中分配对象。它有一些用于对象大小的 size 类,这些对象的大小为 2 的若干次幂减去某一常数。所以,如果您请求给定大小的一个对象,它就简单地分配一个与之匹配的 size 类。这样就提供了一个快速的实现,但是可能会浪费内存。在 参考资料部分中,有一篇描述该实现的文章。 Hoard:编写 Hoard 的目标是使内存分配在多线程环境中进行得非常快。因此,它的构造以锁的使用为中心,从而使所有进程不必等待分配内存。它可以显著地加快那些进行很多分配和回收的多线程进程的速度。在 参考资料部分中,有一篇描述该实现的文章。 众多可用的分配程序中最有名的就是上述这些分配程序。如果您的程序有特别的分配需求,那么您可能更愿意编写一个定制的能匹配您的程序内存分配方式的分配程序。不过,如果不熟悉分配程序的设计,那么定制分配程序通常会带来比它们解决的问题更多的问题。要获得关于该主题的适当的介绍,请参阅 Donald Knuth 撰写的 The Art of Computer Programming Volume 1: Fundamental Algorithms 中的第 2.5 节“Dynamic Storage Allocation”(请参阅 参考资料中的链接)。它有点过时,因为它没有考虑虚拟内存环境,不过大部分算法都是基于前面给出的函数。 在 C++ 中,通过重载 operator new(),您可以以每个类或者每个模板为单位实现自己的分配程序。在 Andrei Alexandrescu 撰写的 Modern C++ Design 的第 4 章(“Small Object Allocation”)中,描述了一个小对象分配程序(请参阅 参考资料中的链接)。 基于 malloc() 的内存管理的缺点 不只是我们的内存管理器有缺点,基于 malloc() 的内存管理器仍然也有很多缺点,不管您使用的是哪个分配程序。对于那些需要保持长期存储的程序使用 malloc() 来管理内存可能会非常令人失望。如果您有大量的不固定的内存引用,经常难以知道它们何时被释放。生存期局限于当前函数的内存非常容易管理,但是对于生存期超出该范围的内存来说,管理内存则困难得多。而且,关于内存管理是由进行调用的程序还是由被调用的函数来负责这一问题,很多 API 都不是很明确。 因为管理内存的问题,很多程序倾向于使用它们自己的内存管理规则。C++ 的异常处理使得这项任务更成问题。有时好像致力于管理内存分配和清理的代码比实际完成计算任务的代码还要多!因此,我们将研究内存管理的其他选择。 回页首 半自动内存管理策略 引用计数 引用计数是一种 半自动(semi-automated)的内存管理技术,这表示它需要一些编程支持,但是它不需要您确切知道某一对象何时不再被使用。引用计数机制为您完成内存管理任务。 在引用计数中,所有共享的数据结构都有一个域来包含当前活动“引用”结构的次数。当向一个程序传递一个指向某个数据结构指针时,该程序会将引用计数增加 1。实质上,您是在告诉数据结构,它正在被存储在多少个位置上。然后,当您的进程完成对它的使用后,该程序就会将引用计数减少 1。结束这个动作之后,它还会检查计数是否已经减到零。如果是,那么它将释放内存。 这样做的好处是,您不必追踪程序中某个给定的数据结构可能会遵循的每一条路径。每次对其局部的引用,都将导致计数的适当增加或减少。这样可以防止在使用数据结构时释放该结构。不过,当您使用某个采用引用计数的数据结构时,您必须记得运行引用计数函数。另外,内置函数和第三方的库不会知道或者可以使用您的引用计数机制。引用计数也难以处理发生循环引用的数据结构。 要实现引用计数,您只需要两个函数 —— 一个增加引用计数,一个减少引用计数并当计数减少到零时释放内存。 一个示例引用计数函数集可能看起来如下所示: 清单 9. 基本的引用计数函数 /* Structure Definitions*/ /* Base structure that holds a refcount */ struct refcountedstruct { int refcount; } /* All refcounted structures must mirror struct * refcountedstruct for their first variables */ /* Refcount maintenance functions */ /* Increase reference count */ void REF(void *data) { struct refcountedstruct *rstruct; rstruct = (struct refcountedstruct *) data; rstruct->refcount++; } /* Decrease reference count */ void UNREF(void *data) { struct refcountedstruct *rstruct; rstruct = (struct refcountedstruct *) data; rstruct->refcount--; /* Free the structure if there are no more users */ if(rstruct->refcount == 0) { free(rstruct); } } REF 和 UNREF 可能会更复杂,这取决于您想要做的事情。例如,您可能想要为多线程程序增加锁,那么您可能想扩展 refcountedstruct,使它同样包含一个指向某个在释放内存之前要调用的函数的指针(类似于面向对象语言中的析构函数 —— 如果您的结构中包含这些指针,那么这是 必需的)。 当使用 REF 和 UNREF 时,您需要遵守这些指针的分配规则: UNREF 分配前左端指针(left-hand-side pointer)指向的值。 REF 分配后左端指针(left-hand-side pointer)指向的值。 在传递使用引用计数的结构的函数中,函数需要遵循以下这些规则: 在函数的起始处 REF 每一个指针。 在函数的结束处 UNREF 第一个指针。 以下是一个使用引用计数的生动的代码示例: 清单 10. 使用引用计数的示例 /* EXAMPLES OF USAGE */ /* Data type to be refcounted */ struct mydata { int refcount; /* same as refcountedstruct */ int datafield1; /* Fields specific to this struct */ int datafield2; /* other declarations would go here as appropriate */ }; /* Use the functions in code */ void dosomething(struct mydata *data) { REF(data); /* Process data */ /* when we are through */ UNREF(data); } struct mydata *globalvar1; /* Note that in this one, we don't decrease the * refcount since we are maintaining the reference * past the end of the function call through the * global variable */ void storesomething(struct mydata *data) { REF(data); /* passed as a parameter */ globalvar1 = data; REF(data); /* ref because of Assignment */ UNREF(data); /* Function finished */ } 由于引用计数是如此简单,大部分程序员都自已去实现它,而不是使用库。不过,它们依赖于 malloc 和 free 等低层的分配程序来实际地分配和释放它们的内存。 在 Perl 等高级语言中,进行内存管理时使用引用计数非常广泛。在这些语言中,引用计数由语言自动地处理,所以您根本不必担心它,除非要编写扩展模块。由于所有内容都必须进行引用计数,所以这会对速度产生一些影响,但它极大地提高了编程的安全性和方便性。以下是引用计数的益处: 实现简单。 易于使用。 由于引用是数据结构的一部分,所以它有一个好的缓存位置。 不过,它也有其不足之处: 要求您永远不要忘记调用引用计数函数。 无法释放作为循环数据结构的一部分的结构。 减缓几乎每一个指针的分配。 尽管所使用的对象采用了引用计数,但是当使用异常处理(比如 try 或 setjmp()/ longjmp())时,您必须采取其他方法。 需要额外的内存来处理引用。 引用计数占用了结构中的第一个位置,在大部分机器中最快可以访问到的就是这个位置。 在多线程环境中更慢也更难以使用。 C++ 可以通过使用 智能指针(smart pointers)来容忍程序员所犯的一些错误,智能指针可以为您处理引用计数等指针处理细节。不过,如果不得不使用任何先前的不能处理智能指针的代码(比如对 C 库的联接),实际上,使用它们的后果通实比不使用它们更为困难和复杂。因此,它通常只是有益于纯 C++ 项目。如果您想使用智能指针,那么您实在应该去阅读 Alexandrescu 撰写的 Modern C++ Design 一书中的“Smart Pointers”那一章。 内存池 内存池是另一种半自动内存管理方法。内存池帮助某些程序进行自动内存管理,这些程序会经历一些特定的阶段,而且每个阶段中都有分配给进程的特定阶段的内存。例如,很多网络服务器进程都会分配很多针对每个连接的内存 —— 内存的最大生存期限为当前连接的存在期。Apache 使用了池式内存(pooled memory),将其连接拆分为各个阶段,每个阶段都有自己的内存池。在结束每个阶段时,会一次释放所有内存。 在池式内存管理中,每次内存分配都会指定内存池,从中分配内存。每个内存池都有不同的生存期限。在 Apache 中,有一个持续时间为服务器存在期的内存池,还有一个持续时间为连接的存在期的内存池,以及一个持续时间为请求的存在期的池,另外还有其他一些内存池。因此,如果我的一系列函数不会生成比连接持续时间更长的数据,那么我就可以完全从连接池中分配内存,并知道在连接结束时,这些内存会被自动释放。另外,有一些实现允许注册 清除函数(cleanup functions),在清除内存池之前,恰好可以调用它,来完成在内存被清理前需要完成的其他所有任务(类似于面向对象中的析构函数)。 要在自己的程序中使用池,您既可以使用 GNU libc 的 obstack 实现,也可以使用 Apache 的 Apache Portable Runtime。GNU obstack 的好处在于,基于 GNU 的 Linux 发行版本中默认会包括它们。Apache Portable Runtime 的好处在于它有很多其他工具,可以处理编写多平台服务器软件所有方面的事情。要深入了解 GNU obstack 和 Apache 的池式内存实现,请参阅 参考资料部分中指向这些实现的文档的链接。 下面的假想代码列表展示了如何使用 obstack: 清单 11. obstack 的示例代码 #include #include /* Example code listing for using obstacks */ /* Used for obstack macros (xmalloc is a malloc function that exits if memory is exhausted */ #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free /* Pools */ /* Only permanent allocations should go in this pool */ struct obstack *global_pool; /* This pool is for per-connection data */ struct obstack *connection_pool; /* This pool is for per-request data */ struct obstack *request_pool; void allocation_failed() { exit(1); } int main() { /* Initialize Pools */ global_pool = (struct obstack *) xmalloc (sizeof (struct obstack)); obstack_init(global_pool); connection_pool = (struct obstack *) xmalloc (sizeof (struct obstack)); obstack_init(connection_pool); request_pool = (struct obstack *) xmalloc (sizeof (struct obstack)); obstack_init(request_pool); /* Set the error handling function */ obstack_alloc_failed_handler = &allocation_failed; /* Server main loop */ while(1) { wait_for_connection(); /* We are in a connection */ while(more_requests_available()) { /* Handle request */ handle_request(); /* Free all of the memory allocated * in the request pool */ obstack_free(request_pool, NULL); } /* We're finished with the connection, time * to free that pool */ obstack_free(connection_pool, NULL); } } int handle_request() { /* Be sure that all object allocations are allocated * from the request pool */ int bytes_i_need = 400; void *data1 = obstack_alloc(request_pool, bytes_i_need); /* Do stuff to process the request */ /* return */ return 0; } 基本上,在操作的每一个主要阶段结束之后,这个阶段的 obstack 会被释放。不过,要注意的是,如果一个过程需要分配持续时间比当前阶段更长的内存,那么它也可以使用更长期限的 obstack,比如连接或者全局内存。传递给 obstack_free() 的 NULL 指出它应该释放 obstack 的全部内容。可以用其他的值,但是它们通常不怎么实用。 使用池式内存分配的益处如下所示: 应用程序可以简单地管理内存。 内存分配和回收更快,因为每次都是在一个池中完成的。分配可以在 O(1) 时间内完成,释放内存池所需时间也差不多(实际上是 O(n) 时间,不过在大部分情况下会除以一个大的因数,使其变成 O(1))。 可以预先分配错误处理池(Error-handling pools),以便程序在常规内存被耗尽时仍可以恢复。 有非常易于使用的标准实现。 池式内存的缺点是: 内存池只适用于操作可以分阶段的程序。 内存池通常不能与第三方库很好地合作。 如果程序的结构发生变化,则不得不修改内存池,这可能会导致内存管理系统的重新设计。 您必须记住需要从哪个池进行分配。另外,如果在这里出错,就很难捕获该内存池。 回页首 垃圾收集 垃圾收集(Garbage collection)是全自动地检测并移除不再使用的数据对象。垃圾收集器通常会在当可用内存减少到少于一个具体的阈值时运行。通常,它们以程序所知的可用的一组“基本”数据 —— 栈数据、全局变量、寄存器 —— 作为出发点。然后它们尝试去追踪通过这些数据连接到每一块数据。收集器到的都是有用的数据;它没有到的就是垃圾,可以被销毁并重新使用这些无用的数据。为了有效地管理内存,很多类型的垃圾收集器都需要知道数据结构内部指针的规划,所以,为了正确运行垃圾收集器,它们必须是语言本身的一部分。 收集器的类型 复制(copying): 这些收集器将内存存储器分为两部分,只允许数据驻留在其中一部分上。它们定时地从“基本”的元素开始将数据从一部分复制到另一部分。内存新近被占用的部分现在成为活动的,另一部分上的所有内容都认为是垃圾。另外,当进行这项复制操作时,所有指针都必须被更新为指向每个内存条目的新位置。因此,为使用这种垃圾收集方法,垃圾收集器必须与编程语言集成在一起。 标记并清理(Mark and sweep):每一块数据都被加上一个标签。不定期的,所有标签都被设置为 0,收集器从“基本”的元素开始遍历数据。当它遇到内存时,就将标签标记为 1。最后没有被标记为 1 的所有内容都认为是垃圾,以后分配内存时会重新使用它们。 增量的(Incremental):增量垃圾收集器不需要遍历全部数据对象。因为在收集期间的突然等待,也因为与访问所有当前数据相关的缓存问题(所有内容都不得不被页入(page-in)),遍历所有内存会引发问题。增量收集器避免了这些问题。 保守的(Conservative):保守的垃圾收集器在管理内存时不需要知道与数据结构相关的任何信息。它们只查看所有数据类型,并假定它们 可以全部都是指针。所以,如果一个字节序列可以是一个指向一块被分配的内存的指针,那么收集器就将其标记为正在被引用。有时没有被引用的内存会被收集,这样会引发问题,例如,如果一个整数域中包含一个值,该值是已分配内存的地址。不过,这种情况极少发生,而且它只会浪费少量内存。保守的收集器的优势是,它们可以与任何编程语言相集成。 Hans Boehm 的保守垃圾收集器是可用的最流行的垃圾收集器之一,因为它是免费的,而且既是保守的又是增量的,可以使用 --enable-redirect-malloc 选项来构建它,并且可以将它用作系统分配程序的简易替代者(drop-in replacement)(用 malloc/ free 代替它自己的 API)。实际上,如果这样做,您就可以使用与我们在示例分配程序中所使用的相同的 LD_PRELOAD 技巧,在系统上的几乎任何程序中启用垃圾收集。如果您怀疑某个程序正在泄漏内存,那么您可以使用这个垃圾收集器来控制进程。在早期,当 Mozilla 严重地泄漏内存时,很多人在其中使用了这项技术。这种垃圾收集器既可以在 Windows® 下运行,也可以在 UNIX 下运行。 垃圾收集的一些优点: 您永远不必担心内存的双重释放或者对象的生命周期。 使用某些收集器,您可以使用与常规分配相同的 API。 其缺点包括: 使用大部分收集器时,您都无法干涉何时释放内存。 在多数情况下,垃圾收集比其他形式的内存管理更慢。 垃圾收集错误引发的缺陷难于调试。 如果您忘记将不再使用的指针设置为 null,那么仍然会有内存泄漏。 回页首 结束语 一切都需要折衷:性能、易用、易于实现、支持线程的能力等,这里只列出了其中的一些。为了满足项目的要求,有很多内存管理模式可以供您使用。每种模式都有大量的实现,各有其优缺点。对很多项目来说,使用编程环境默认的技术就足够了,不过,当您的项目有特殊的需要时,了解可用的选择将会有帮助。下表对比了本文中涉及的内存管理策略。 表 1. 内存分配策略的对比 策略 分配速度 回收速度 局部缓存 易用性 通用性 实时可用 SMP 线程友好 定制分配程序 取决于实现 取决于实现 取决于实现 很难 无 取决于实现 取决于实现 简单分配程序 内存使用少时较快 很快 差 容易 高 否 否 GNU malloc 中 快 中 容易 高 否 中 Hoard 中 中 中 容易 高 否 是 引用计数 N/A N/A 非常好 中 中 是(取决于 malloc 实现) 取决于实现 池 中 非常快 极好 中 中 是(取决于 malloc 实现) 取决于实现 垃圾收集 中(进行收集时慢) 中 差 中 中 否 几乎不 增量垃圾收集 中 中 中 中 中 否 几乎不 增量保守垃圾收集 中 中 中 容易 高 否 几乎不 参考资料 您可以参阅本文在 developerWorks 全球站点上的 英文原文。 Web 上的文档 GNU C Library 手册的 obstacks 部分 提供了 obstacks 编程接口。 Apache Portable Runtime 文档 描述了它们的池式分配程序的接口。 基本的分配程序 Doug Lea 的 Malloc 是最流行的内存分配程序之一。 BSD Malloc 用于大部分基于 BSD 的系统中。 ptmalloc 起源于 Doug Lea 的 malloc,用于 GLIBC 之中。 Hoard 是一个为多线程应用程序优化的 malloc 实现。 GNU Memory-Mapped Malloc(GDB 的组成部分) 是一个基于 mmap() 的 malloc 实现。 池式分配程序 GNU Obstacks(GNU Libc 的组成部分)是安装最多的池式分配程序,因为在每一个基于 glibc 的系统中都有它。 Apache 的池式分配程序(Apache Portable Runtime 中) 是应用最为广泛的池式分配程序。 Squid 有其自己的池式分配程序。 NetBSD 也有其自己的池式分配程序。 talloc 是一个池式分配程序,是 Samba 的组成部分。 智能指针和定制分配程序 Loki C++ Library 有很多为 C++ 实现的通用模式,包括智能指针和一个定制的小对象分配程序。 垃圾收集器 Hahns Boehm Conservative Garbage Collector 是最流行的开源垃圾收集器,它可以用于常规的 C/C++ 程序。 关于现代操作系统中的虚拟内存的文章 Marshall Kirk McKusick 和 Michael J. Karels 合著的 A New Virtual Memory Implementation for Berkeley UNIX 讨论了 BSD 的 VM 系统。 Mel Gorman's Linux VM Documentation 讨论了 Linux VM 系统。 关于 malloc 的文章 Poul-Henning Kamp 撰写的 Malloc in Modern Virtual Memory Environments 讨论的是 malloc 以及它如何与 BSD 虚拟内存交互。 Berger、McKinley、Blumofe 和 Wilson 合著的 Hoard -- a Scalable Memory Allocator for Multithreaded Environments 讨论了 Hoard 分配程序的实现。 Marshall Kirk McKusick 和 Michael J. Karels 合著的 Design of a General Purpose Memory Allocator for the 4.3BSD UNIX Kernel 讨论了内核级的分配程序。 Doug Lea 撰写的 A Memory Allocator 给出了一个关于设计和实现分配程序的概述,其中包括设计选择与折衷。 Emery D. Berger 撰写的 Memory Management for High-Performance Applications 讨论的是定制内存管理以及它如何影响高性能应用程序。 关于定制分配程序的文章 Doug Lea 撰写的 Some Storage Management Techniques for Container Classes 描述的是为 C++ 类编写定制分配程序。 Berger、Zorn 和 McKinley 合著的 Composing High-Performance Memory Allocators 讨论了如何编写定制分配程序来加快具体工作的速度。 Berger、Zorn 和 McKinley 合著的 Reconsidering Custom Memory Allocation 再次提及了定制分配的主题,看是否真正值得为其费心。 关于垃圾收集的文章 Paul R. Wilson 撰写的 Uniprocessor Garbage Collection Techniques 给出了垃圾收集的一个基本概述。 Benjamin Zorn 撰写的 The Measured Cost of Garbage Collection 给出了关于垃圾收集和性能的硬数据(hard data)。 Hans-Juergen Boehm 撰写的 Memory Allocation Myths and Half-Truths 给出了关于垃圾收集的神话(myths)。 Hans-Juergen Boehm 撰写的 Space Efficient Conservative Garbage Collection 是一篇描述他的用于 C/C++ 的垃圾收集器的文章。 Web 上的通用参考资料 内存管理参考 中有很多关于内存管理参考资料和技术文章的链接。 关于内存管理和内存层级的 OOPS Group Papers 是非常好的一组关于此主题的技术文章。 C++ 中的内存管理讨论的是为 C++ 编写定制的分配程序。 Programming Alternatives: Memory Management 讨论了程序员进行内存管理时的一些选择。 垃圾收集 FAQ 讨论了关于垃圾收集您需要了解的所有内容。 Richard Jones 的 Garbage Collection Bibliography 有指向任何您想要的关于垃圾收集的文章的链接。 书籍 Michael Daconta 撰写的 C++ Pointers and Dynamic Memory Management 介绍了关于内存管理的很多技术。 Frantisek Franek 撰写的 Memory as a Programming Concept in C and C++ 讨论了有效使用内存的技术与工具,并给出了在计算机编程中应当引起注意的内存相关错误的角色。 Richard Jones 和 Rafael Lins 合著的 Garbage Collection: Algorithms for Automatic Dynamic Memory Management 描述了当前使用的最常见的垃圾收集算法。 在 Donald Knuth 撰写的 The Art of Computer Programming 第 1 卷 Fundamental Algorithms 的第 2.5 节“Dynamic Storage Allocation”中,描述了实现基本的分配程序的一些技术。 在 Donald Knuth 撰写的 The Art of Computer Programming 第 1 卷 Fundamental Algorithms 的第 2.3.5 节“Lists and Garbage Collection”中,讨论了用于列表的垃圾收集算法。 Andrei Alexandrescu 撰写的 Modern C++ Design 第 4 章“Small Object Allocation”描述了一个比 C++ 标准分配程序效率高得多的一个高速小对象分配程序。 Andrei Alexandrescu 撰写的 Modern C++ Design 第 7 章“Smart Pointers”描述了在 C++ 中智能指针的实现。 Jonathan 撰写的 Programming from the Ground Up 第 8 章“Intermediate Memory Topics”中有本文使用的简单分配程序的一个汇编语言版本。 来自 developerWorks 自我管理数据缓冲区内存 (developerWorks,2004 年 1 月)略述了一个用于管理内存的自管理的抽象数据缓存器的伪 C (pseudo-C)实现。 A framework for the user defined malloc replacement feature (developerWorks,2002 年 2 月)展示了如何利用 AIX 中的一个工具,使用自己设计的内存子系统取代原有的内存子系统。 掌握 Linux 调试技术 (developerWorks,2002 年 8 月)描述了可以使用调试方法的 4 种不同情形:段错误、内存溢出、内存泄漏和挂起。 在 处理 Java 程序中的内存漏洞 (developerWorks,2001 年 2 月)中,了解导致 Java 内存泄漏的原因,以及何时需要考虑它们。 在 developerWorks Linux 专区中,可以到更多为 Linux 开发人员准备的参考资料。 从 developerWorks 的 Speed-start your Linux app 专区中,可以下载运行于 Linux 之上的 IBM 中间件产品的免费测试版本,其中包括 WebSphere® Studio Application Developer、WebSphere Application Server、DB2® Universal Database、Tivoli® Access Manager 和 Tivoli Directory Server,查 how-to 文章和技术支持。 通过参与 developerWorks blogs 加入到 developerWorks 社区。 可以在 Developer Bookstore Linux 专栏中定购 打折出售的 Linux 书籍。 关于作者 Jonathan Bartlett 是 Programming from the Ground Up 一书的作者,这本书介绍的是 Linux 汇编语言编程。Jonathan Bartlett 是 New Media Worx 的总开发师,负责为客户开发 Web、视频、kiosk 和桌面应用程序。您可以通过 [email protected] 与 Jonathan 联系。
双链路网络安全解决方案 需求分析: 为业务提供所承诺的7/24的可靠服务是至关重要的。一个提供Internet接入和网站访问的服务商不仅需要保证链路和网站内所有的WEB服务器、应用服务器和数据库服务器的高可用性,还必须保证链路和站点本身的高可用性。 保证Internet接入的稳定性对于Internet服务商来说是非常重要的。现在的服务商采用一条Internet接入,也就是说使用一个ISP的链路。显然,一个ISP无法保证它提供的Internet链路的持续可用性,从而可能导致Internet访问和网站WAN接入的中断,而Internet接入的中断则意味着高额的损失。 一个企业可以采用多链路(Multi-Homing)和集群HA的解决方案来避免Internet接入中断所造成的损失。在这里所提及的"Multi-Homing"通常指同时使用不同ISP提供的多条Internet接入链路;"集群HA"是指在接入点利用同品牌通型号的两个或者多个防火墙形成互为备份/冗余的功能。由于多链路解决方案能够提供更好的可用性和性能,它正在被越来越多的Internet服务商和企业所采用。可用性的提高来自于多条链路的使用,而性能提高则是因为同时使用多条链路增加了带宽,而加入集群的同时更加保护网络不受因单点故障而导致网络中断的风险。 方案描述 双链路网络安全解决方案全文共7页,当前为第1页。多链路冗余起到在多个运营商之间故障的转移,但是防火墙作为内外网的接入点,当设备出现故障便会导致内外网之间的网络业务的全部中断,引起单点故障,影响业务正常运行。因此在网络接入点部署多台设备形成备份/冗余是非常必要的,其中一台设备发生故障时,数据便会切换到另外一台设备上继续传输,而且还可以做设备性能的叠加增强。下面是网络拓扑图: 双链路网络安全解决方案全文共7页,当前为第1页。 功能实现 3.1双链路功能 3.1.1 对于外向型连接 多重连接将以速度为目标对外向型互联网连接进行优化。多重连接使用来自于各个ISP的源IP地址检测与服务器的连接情况。反馈速度最快的连接可以继续进行工作。因此,每个连接都必定是速度最快的连接,其结果是,综合数据吞吐率将远远超过一个服务性能不稳定的单个连接。经过累加,暂时性工作性能高峰将为整个系统的工作带来优势,还可以避免延迟现象的发生。 3.1.2 对于内向型连接 多重连接技术中将对内向型连接进行负载均衡,并以获得最高水平的可用性为目标而进行优化,因此,用户在访问您的站点时将不会出现延迟现象或服务中断。通过对服务器使用特殊IP地址,多重连接技术将可以实现这一目标;此时,服务器上将被配置多个IP地址,而这些IP地址来自于由多个ISP所分配的IP地址范围当中。 3.1.3 线路负载均衡原理 双链路网络安全解决方案全文共7页,当前为第2页。通过Watchguard卓越有效的Link Load Balancing功能为总部多条ISP多条链路无缝实现链路负载均衡。 双链路网络安全解决方案全文共7页,当前为第2页。 目前Watchguard可实现多种负载均衡方式: Routing table:本方式通常用来解决南电信北网通互通难的问题,从而实现访问电信线路出去访问电信网络,反之通过网通线路出去。 Failover:线路备份,Watchguard提供备份优先级,并可指定那些预留线路不参与线路备份,保证关键业务的持续有效。 Round-robin:真正的负载均衡实现多条链路的叠加,Watchguard也可以指定预留线路不参与负载均衡。对不同质量的线路也可以加权处理。 Interface Overflow:通过这种负载均衡的方式可以保证每条链路的带宽都能充分利用从而实现投资最大化。 3.1.4 线路切换机制 通过配置多链路事件的粘滞连接、故障回复来实现线路之间的相互切换。 粘滞连接:在规定的时间段内持续使用同一个WAN 接口的连接。在为多WAN 使用"循环法"或"接口溢出"选项时,可以设置粘滞连接参数。粘滞特性可确保:当数据包通过某个外部接口发送出去时,在指定时间段内,源IP 地址和目标IP 地址对之间的所有未来的数据包都使用同一个外部接口。默认情况下,粘滞连接会在3 分钟内使用同一个接口。 故障回复:当发生故障转移事件时希望WatchGuard 设备执行的操作,使主外部接口重新处于活动状态。发生此情况后,所有新连接将立即故障回复到主外部接口。可以选择在发生故障回复时为正在处理的连接使用此方法。 3.2 集群功能 3.2.1 触发故障转移的事件 群集主控设备的被监控接口出现链路故障 如果群集主控设备的被监控接口无法发送或接收流量,将触发故障转移。您可以在 Policy Manager 的FireCluster 配置中查看被监控接口的列表。 双链路网络安全解决方案全文共7
一、需求分析 1、为每个部门建立一个文件夹,文件夹允许对应部门的人员进行完全权限 的访问,领导可进行 只读访问,其他人员不能访问。 2、建立 "常用 软件 "文件夹,计算机管理人员可以进行完全权限访问,其他人员进行只读访问 。 3、建立 "公司发文 "文件夹,发文人员进行读写访问,其他人员进行只读访问。 4、建立 "中转站 "文件夹,用于人员之间的资料互换,所有人员具有读写权限。 5、建立 "常用报表 "文件夹,其中设立各类报表的子文件夹,并对子文件夹设立权限。 需要修改其中内容的人员具有读写权限, 只需查看的人员具有只读权限, 其他人员无权访问。 (具 体人员和相关访问权限另附) 二、设备配置 1、购买一台 服务器 计算机,并建好局域网。 2、服务器上 安装 Windows 服务器操作系统,如 Windows Server 2003。 3、安装文件服务器,文件服务器是 Windows Server 的一个组件。 4、服务器上至少有一个 NTFS 格式的磁盘分区,用于存放共享的资源。 三、文件夹建立 1、在 NTFS 格式的分区上建立一个文件夹作为共享根目录。 2、在根目录下建立各个分目录文件夹。如常用软件、常用报表、中转站、 人力部、技术部、进 出口部等。 3、在分目录下建立子目录文件夹。如常用报表下的生产日报表、船期表、 纸样图等。(图 2) 四、建立用户和组 1、在服务器上为每个计算机用户建立一个用户。 开始 —— 设置 —— 控制面板 —— 管理工具 —— 计算机管理 选择本地用户和组 —— 选择 "用户 " 在空白处点击右键,选择 "新建用户 "出现下图界面。 输入 "用户名 "(登录时使用)、 "描述 "、 "密码 ",并取消 "用户下次登录时必须更改密码 "前的小勾。 点击 "创建 "。 以此类推,建立所有用户。 2、在服务器上建立用户组 开始 —— 设置 —— 控制面板 —— 管理工具 —— 计算机管理 选择本地用户和组 —— 选择 "组" 在空白处点击右键,选择 "新建组 "出现下图界面。 输入 "组名 "、 "描述 " 点击 "添加 "选中相应的用户,将用户加为组成员。 点击 "创建 "。 以此类推,建立所有组(部门)。 五、设置文件夹共享及权限。 1、文件夹共享 到希望共享的文件夹;右键弹出菜单,选择 "共享和安全 " 选择 "共享 ",选择 "共享此文件夹 " 点击 "权限 "按钮,出现权限对话框。 通过点击 "添加 "——"高级 "——"立即查 ",选择要添加的用户和组,之后点击 "确认 "。 为不同的用户和组设置相应的共享权限。设置完成后点击 "确认 "。 2、权限设置 有时只设置了共享的权限,还不能对文件夹中的文件进行写操作。这时就需 要进行 "安全权限 " 的设定: 到对应的文件夹,右键弹出菜单,选择 "属性 " 选择 "安全 " 通过点击 "添加 "——"高级 "——"立即查 ",选择要添加的用户和组,之后点击 "确认 "。 为不同的用户和组设置相应的共享权限。设置完成后点击 "确认 "。 3、子菜单权限设定 有时共享文件夹的子文件夹需要另外进行新的权限分配。 这时需要进行子文件夹 "安全权限 "的设 定: 到对应的子文件夹,右键弹出菜单,选择 "属性 " 选择 "安全 " 点击 "高级按钮 ",弹出 "高级安全设置对话框 " 将 "从父项继承那些可以应用到子对象的权限项目,包括那些在此明确定义的 项目 "前面的 " "取 消。在弹出的对话框中点 "删除 "按钮。 点击 "确定 "按钮。 通过点击 "添加 "——"高级 "——"立即查 ",选择要添加的用户和组,之后点击 "确认 "。 为不同的用户和组设置相应的共享权限。设置完成后点击 "确认 "。 其他 : 1、服务器远程登陆方式要选为 "经典 "方式 开始 —— 控制面板 —— 管理工具 —— 本地安全策略 选择 "本地策略 "——"安全选项 " 到 "网络访问:本地帐户的共享和安全模式 "项,将其设置为 "经典 -本地用户以自己的身份验证 "。 2、家庭版的系统会默认用 GUEST 用户登录,如果服务器开启了 GUEST 用户且没有设置密码,则会默认使用 GUEST 用户登录服务器。将服务器的 GUSET 用户禁用后,家庭版的计算机登录 服务器时会弹出登录框。 ----------------------- 服务器解决方案全文共4页,当前为第1页。 服务器解决方案全文共4页,当前为第2页。 服务器解决方案全文共4页,当前为第3页。 服务器解决方案全文共4页,当前为第4页。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值