分类: 服务器

服务器

基于ARM+Linux系统的智能家居系统

该项目为基于ARM的智能家居系统。系统采用Tiny4412开发板作为中控端,节点使用了两个stm32开发板,通信采用zigbee模块,包含了安防系统,照明系统,环境系统等,并且拥有良好的人机交互界面。

功能简介

1.安防系统

1)智能门禁功能。实现刷卡和密码锁两种开门方式,实现可以查看访客记录,密码连续错误触发报警等功能。同时管理员模式可以增加删除用户和修改密码,门卡挂失功能等。

2)火灾检测功能。采用气体传感器和火焰传感器实现火灾和煤气泄漏检测,当火灾发生时可自动向用户报警。
3)自动报警功能。户外模式下若检测到家中有人,节点会查询门禁系统是否被正常打开,若没有则向用户报警。
4)监控功能。基于Linux下的视频监控系统,摄像头可进行监控,用户在接到节点报警时可以选择打开摄像头,还可截图并查看。
2.照明系统
1)使用热释电模块和GY-30模块实现当有人经过并且光线很暗时自动打开灯,一段时间后自动熄灭。
2)利用pwm波和Zigbee实现可自己从中控端调节节点每个灯的亮度。
3)利用GY-30模块和pwm波实现根据光照强度的变化自动调节灯光亮度。
3.环境系统
1)使用DHT11和GY-30模块分别采集室内温湿度和光照强度,并在中控端要求查看时发送,用户可根据需要调节; 2)使用电机模拟窗帘开闭,可自己调节电机转的方向和圈数。
3)使用气体传感器和火焰传感器实现火灾和煤气泄漏实时检测报告。
4)使用热释电模块检测家中是否有人。

移动端原生app、混合app、webapp 区别

原生app:
安卓操作系统:java语言是安卓系统开发原生语言,原生app

IOS操作系统:object-c 语言是原生app

特点:比较快捷的使用设备端提供的接口,处理速度上有优势。

混合app:
控件:UI webview 可以假装网页,加载网址,直接有原生打包生成app

遇到设备端的拍照、音频处理、视频录制等等操作,需要使用原生方式调取,HTML5只是提供了展示形式,采用的操作javascript;

中间件:phonegap appcan 生成app应用。

特点:展示方面开发效率比原生开发效率更高,人员成本,时间成本上;

WEB APP
还是基于网站本身,利用HTML5技术实现移动端浏览器浏览体现更好展示和应用

比如:微信中的公众号,创建桌面快捷方式,直接进入公众号。

百度提供轻应用,直达号等。

Web与App的五种关系及演变

Web与App的五种关系及演变

本文会阐述Web与App的五种关系类型,以及从流量分发视角和技术演进视角看待关系的演变。

五种关系类型

对于移动端应用来说,Web与App的关系可以分为五种基本类型。移动互联网发展的整体趋势决定了主流的关系类型。每个具体的产品也会随着发展阶段的不同而采用不同的形态,或者各种形态混合共存。

Web or App – 独立应用

Web与App各自独立完成服务。这种模式下Web与App实现的业务可以是差异化的,但各自保持独立且完整,相互之间的交互基本仅限于流量引导。

App从应用商店获取流量,占总流量的主要部分。Web应用独立运行在浏览器中,从搜索引擎获取长尾流量。Web应用可以灵活处理用户的随机需求,在服务过程中找机会将用户引导至App。

Web in App – 壳型混合应用

App作为Web应用的壳资源。App提供的容器能让Web能够突破浏览器的限制实现某些功能。更重要的是有了App的壳就能够利用App的应用商店作为分发渠道。早期的Facebook App就是典型的壳应用。

Web on App – 平台型混合应用

App作为平台承载各种Web应用。平台型App会提供容器让其它合作方以相对独立的Web应用的形式接入平台。平台上的Web应用可以获得部分扩展功能和用户信息。微信公众号和支付宝服务窗就是这种模式的代表。

Web and App – 综合型混合应用

Web与App高度混合,共同实现某项业务。这种模式下原生部分与Web部分会有大量的交互。为了达到用户体验的一致性,App会加强容器的能力,让Web部分能够调用更多的Native资源,以弥补Web部分在体验上的不足。在这类应用中,用户通常难以区分哪些部分是Web,哪些部分是原生。美团、携程等综合型服务商会大量采用这种模式。

Web of App – 融合型应用

使用Web技术来做App。不用Webview来做混合嵌入,而是直接借用部分Web技术来实现原生的功能。这种模式是既要Native的体验,又要Web动态更新与代码复用的好处。微信小程序就是这种模式的代表。

流量分发视角

移动时代到来之前,互联网产品主要以PC端的Web应用为主,入口主要是搜索引擎。早期用户逐渐向移动设备上迁移时,依然保持着使用浏览器和搜索引擎的习惯,这个时候有独立的移动端Web应用来获取流量并完成服务就很重要。

随着App的崛起,流量的来源从搜索引擎变成了应用市场,这个时候主战场就由浏览器转向了App,混合应用应运而生。

一部分App获得市场*对优势地位之后,就会形成头部效应,做流量的二次分发,这类App中接入的应用也就是平台型混合应用。

头部效应与二次分发:

头部App发展到后期,就会有资本挑战已经成熟的Webview嵌入模式,引导合作方做技术融合型应用。合作方会付出更多的开发成本来换取体验上的提升和更多的流量支持。这种做法能够提高技术壁垒,形成差异化与体验优势来巩固头部App自身的地位。

在移动互联网时代,App是主要的流量载体,但从内容生产和消费层面上并没有统一标准,自然就造成了开发成本的大幅上升。

为了降低成本,App从PC时代将Web的标准和内容迁移过来,混合应用应运而生。

混合应用发展到后期,由于头部App厂商的技术和流量优势的持续积累,同时原有的Web标准的演进速度又不及预期,导致头部App可以有实力去掉Web容器这一中间层,直接推行新的内容标准,这些内容标准大量借鉴并且继承了原有的Web标准,同时又更贴近了App的使用场景。

腾讯的微信小程序和Facebook的React Native虽然商业目的上各有不同,但从技术上来讲都是去掉了Web容器这一层,将Web标准延伸到Native领域。

总结

本文阐述了Web与App的五种基本关系类型以及他们各自的产生背景和特点。

从商业角度来看,互联网产品获取流量就像生物需要获取食物一样重要,所以产品形态一定会向流量入口所需要的方向倾斜。

从技术角度来看,Web标准是移动互联网从PC时代继承的技术遗产,未来会有各种基于传统Web标准的新标准产生,另一方面Web标准自身会持续演进以适应移动互联网的快速发展。

这也正说明了一个问题,互联网发展离不开前端开发,而前端开发在app的开发中占据了一定行主导的位置,斑码教育正是看到了这一发展趋势,联合行业大牛研发出一整套全栈前端的实用性课程,专注于现在行业方向,提供从就业角度出发的技术服务,保障学员毕业薪资,,持续关注我进行了解前端知识。

Web端与APP端区别

Web与APP区别:
1、web基于浏览器, app必须要有客户端
2、web关注响应时间,app还需要关注流量、电量、手机本身的硬件条件
3、兼容方面,web是浏览器兼容,选择不同的浏览器内核,app是手机,有不同品牌,android和ios系统,还需要看屏幕分辨率、屏幕尺寸,和其它app之间的兼容
4、网络环境,App还有不同网络环境,2G、3G、4G、wifi、断网
5、硬件环境,App还需考虑异常场景:中断、关机、死机、重启等
6、交叉事件,接听电话、短信、邮件、其它操作
7、App有横屏和竖屏之分、溢屏、触屏和手势
8、Web直接连接服务器,app的取值方式可能是服务器、接口或本地缓存
9、升级、更新,Web更新无提示,直接进入浏览器就是*新,app是需要自己进行更新才能获取*新数据
10、web登录需要密码,除非设置的记住密码,App有免登录功能

标准区别:

兼容性测试:web兼容各种版本浏览器,app兼容各种操作系统、手机型号、版本
手势:web没有,app有手势测试、功能键测试
交叉事件和横竖屏测试:app需要测试和其它app的兼容,与通话、短信之间的交叉
安装测试:web的bs架构,客户端不需要安装,手机app需要安装测试
更新:web一般更新服务端,app更新会对客户端进行更新,需要对更新进行测试
网络:app需要测试网络之间的切换,以及断网情况下,不同的网络类型对app是否有影响
屏幕的限制:app需要关注不同的屏幕上传的图片,文字的显示效果,是否会溢屏
性能测试:web需要关注页面的响应时间,app除了要考虑响应时间,还需要考虑到耗电量和流量消耗
软件的运行和启动:移动端需要测试app的启动,卸载和升级

Arm处理器与Linux的完美结合

嵌入式系统的定义应当是以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
比如现在ATM取款机就是一个典型RTOS,embedded os主要包括两部分,一部分是处理器,比如Arm,POWERPC,MIPC,一部分是OS,比如Linux,wince,vxworks,us/os,etc.我现在主要学习的路线是arm+linux,选择arm主要是因为arm技术已经比较成熟,选择linux是因为linux是开源的,免费的,另外如果学好了linux就算将来不搞嵌入式系统开发这块,也可以专供linux服务器这一方面。

学习嵌入式linux,主要做的就是四点,一点就是写bootloader,并移植到到nand flash上,第二点,编译kernel,并通过bootloader下载到nand flash上,第三点,在基于nand flash上建立文件系统,第四点,把写好的应用程序下载到target上。基本流程就是这么下来的,具体到开发板上时可能就有所差别了,下边就以深圳优龙公司的fs2410为目标板具体的上述一下开发的流程,以及在开发中应注意的问题。想交流了解3306607541
*步:交叉编译环境的建立

A: 基于linux操作系统的应用开发环境一般是由目标系统硬件(开发板)和宿主pc机所构成。目标硬件开发板用于运行操作系统和系统应用软件。而目标板所用到的操作系统的内核编译、应用程序的开发和调试则需要通过宿主pc机来完成(所以称为交叉编译)。双方之间一般通过串口,并口或以太网接口建立连接关系。安装linux os,比如redhao linux 9.0,可以采用默认安装(但要包含ftp服务),将该linux服务器接入局域网,其他的pc机可以用windows,需要的软件工具包括。

(1)ftp客户端程序

(2)telnet工具

(3)移植到某一特定arm平台的linux操作系统内核源码

(4)gnu编译工具,可由相关网站下载

在某工作站pc上安装ftp客户端程序和telnet工具,linux os kernel的编译一般有一个比较固定的步骤,会根据Makefiel文件的不同而略有差异,可参考相关文档,按固定的步骤编译内核完成以后,会在相应目录生成可执行的二进制文件,通过ftp传到pc机上,热后通过串口或网络下载到开发板上。

B:(1) 创建编译环境,在这个过程中,将设置一些环境变量,创建安装目录,安装内核源代码和头文件等。

(2) 创建binutils.在这个过程结束后,会创建类似arm-linux-ld等工具。

(3) 创建一个交叉编译版本的gcc,注意:在这个过程中,只能编译c程序,而不能编译c++程序。

(4) 创建一个交叉编译版本的glibc,这里*容易出问题。

(5) 创建一个交叉编译版本的gdb。这个过程结束后,会创建arm-linux_gdb

(6) 重新创建gcc。前面创建gcc的过程没有编译c++编译器,现在glibc已经准备好了,所以这个步骤将完善gcc的交叉编译。

(7) 重新创建glibc.

如果在交叉编译过程中出现错误,那么请检查:

版本选择是否正确,以及是否安装了相应的补丁;

库文件路径设置是否正确;

系统环境变量是否设置正确。

第二步:编写bootloader并移植到开发板上

A:bootloader(引导加载程序)是系统加电后运行的*段代码。嵌入式系统中的bootloader相当于pc机中的bios。大多数bootloader都包含两种不同的操作模式,一种是启动加载(bootloading)模式,在这种模式下,bootloader从目标机上的某个固态存储器设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是bootloader的正常工作模式,另一种是下载(downloading)模式。在这种模式下,目标机上的bootloader将通过串口或网络等通信手段从开发主机(host)上下载内核映像和根文件系统映像等到RAM中。然后可以再被bootloader写到目标机上的固态存储介质上。

B:bootloader启动大多数都分为两个阶段

(1):基本的硬件初始化(屏蔽所有的中断,关闭处理器内部指令/数据cache等)。

为第二阶段准备RAM空间,如果是从某个固态存储媒质中,则复制bootlodaer的第二阶段代码到RAM。

设置堆栈。

跳转到第二阶段的C程序入口点。

(2):初始化本阶段要使用的硬件设备。

检查系统内存映射。

将内核映像和根文件系统映像从flash读到RAM。

为内核设置启动参数调用内核。

嵌入式系统、linux和嵌入式linux的区别

这几个东西比较容易混淆

嵌入式系统:

IEEE(国际电气和电子工程师协会)对嵌入式系统的定义:“用于控制、监视或者辅助操作机器和设备的装置”。原文为:Devices Used to Control,Monitor or Assist the Operation of Equipment,Machinery or Plants)。

嵌入式系统是一种专用的计算机系统,作为装置或设备的一部分。通常,嵌入式系统是一个控制程序存储在ROM中的嵌入式处理器控制板。事实上,所有带有数字接口的设备,如手表、微波炉、录像机、汽车等,都使用嵌入式系统,有些嵌入式系统还包含操作系统,但大多数嵌入式系统都是是由单个程序实现整个控制逻辑。

国内普遍认同的嵌入式系统定义为:以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。嵌入式系统的核心是由一个或几个预先编程好以用来执行少数几项任务的微处理器或者单片机组成。与通用计算机能够运行用户选择的软件不同,嵌入式系统上的软件通常是暂时不变的;所以经常称为“固件”。

linux:

Linux是一种自由和开放源码的类Unix操作系统,存在着许多不同的Linux版本,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。Linux是一个*的操作系统,世界上运算*快的10台超级计算机运行的都是Linux操作系统。严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。

Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。它主要用于基于Intel x86系列CPU的计算机上。这个系统是由全世界各地的成千上万的程序员设计和实现的。其目的是建立不受任何商品化软件的版权制约的、全世界都能自由使用的Unix兼容产品。

Linux以它的高效性和灵活性著称,Linux模块化的设计结构,使得它既能在价格昂贵的工作站上运行,也能够在廉价的PC机上实现全部的Unix特性,具有多任务、多用户的能力。Linux是在GNU公共许可权限下免费获得的,是一个符合POSIX标准的操作系统。Linux操作系统软件包不仅包括完整的Linux操作系统,而且还包括了文本编辑器、高级语言编译器等应用软件。它还包括带有多个窗口管理器的X-Windows图形用户界面,如同我们使用Windows NT一样,允许我们使用窗口、图标和菜单对系统进行操作。

嵌入式linux:  

嵌入式Linux系统就是利用Linux其自身的许多特点,把它应用到嵌入式系统里。随着微处理器的产生,价格低廉、结构小巧的CPU和外设连接提供了稳定可靠的硬件架构,那么限制嵌入式系统发展的瓶颈就突出表现在了软件方面。尽管从八十年代末开始,陆续出现了一些嵌入式操作系统,比较著名的有Vxwork、pSOS、Neculeus和Windows CE。但这些专用操作系统都是商业化产品,其高昂的价格使许多低端产品的小公司望而却步;而且,源代码封闭性也大大限制了开发者的积*性。另外,结合国内实情,当前国家对自主操作系统的大力支持,也为源码开放的LINUX的推广提供的广阔的发展前景。还有,对上层应用开发者而言,嵌入式系统需要的是一套高度简练、界面友善、质量可靠、应用广泛、易开发、多任务,并且价格低廉的操作系统。在不久的将来,从冰箱到收音机都会内置处理器。因为Linux的开放性,许多人认为Linux非常适合多数Internet设备。他们认为Linux可以支持不同的设备,支持不同的配置。 

Linux做嵌入式的优势,首先,Linux是开放源代码的,不存在黑箱技术,遍布全球的众多Linux爱好者又是Linux开发者的强大技术支持;其次,Linux的内核小、效率高,内核的更新速度很快;第三,Linux是免费的OS,在价格上*具竞争力。 

Linux还有着嵌入式操作系统所需要的很多特色,突出的就是Linux适应于多种CPU和多种硬件平台,是一个跨平台的系统。到目前为止,它可以支持二三十种CPU。而且性能稳定,裁剪性很好,开发和使用都很容易。很多CPU包括家电业芯片,都开始做Linux的平台移植工作。移植的速度远远超过Java的开发环境。也就是说,如果今天用Linux环境开发产品,那么将来换CPU就不会遇到困扰。同时,Linux内核的结构在网络方面是非常完整的,Linux对网络中*常用的TCP/IP协议有*完备的支持。提供了包括十兆、百兆、千兆的以太网络,以及无线网络,Toker ring(令牌环网)、光纤甚至卫星的支持。所以Linux很适于做信息家电的开发。 

还有使用Linux为的是来开发无线连接产品的开发者越来越多。Linux在快速增长的无线连接应用主场中有一个非常重要的优势,就是有足够快的开发速度。这是因为LInux有很多工具,并且Linux为众多程序员所熟悉。因此,我们要在嵌入式系统中使用Linux操作系统。 

Linux的大小适合嵌入式操作系统──Linux固有的模块性,适应性和可配置性,使得这很容易做到。另外,Linux源码的实用性和成千上万的程序员热切其望它用于无数的嵌入式应用软件中,导致很多嵌入式Linux的出现,包括:Embedix,ETLinux,LEM,Linux Router Project,LOAF,uCLinux,muLinux,ThinLinux,FirePlug,Linux和PizzaBox Linux。

ARM LINUX与普通LINUX区别

相对于ARM linux,我们说的普通linux指的是X86 linux,他们都是linux系统,但是由于ARM和X86是不同的CPU架构,他们的指令集不同,所以软件编译环境不同,软件代码一般不能互用,一般需要进行兼容性移植。
X86是经典的CISC指令集,指令集复杂,功能多,串行执行,但是也意味着执行效率低下,但性价比突出,所以称为民用终端的主流处理器内置指令集。Intel和AMD的家用处理器都是X86指令集。以X86为代表的CISC,理论并发线程1-2条。
ARM是Advanced RISC Machine 的缩写。它的指令集比RISC还要精简。通常使用ARM架构处理器的机型,多为嵌入式或者便携机。主频通常不高,现在高通公司的ARM架构处理器有1.0GHz的,已经算相当高了。另外,ARM 7沿用冯·诺依曼结构;而从ARM 9以后,就都采用了哈佛结构。ARM的并发线程,理论上有4条左右,处理效率较X86高不少。

arm服务器 linux,Linux之父:ARM服务器没戏!

是什么引发了Linus Torvalds放炮?

答案是ARM近期宣布的新品Neoverse N1平台和E1 CPU。

ARM表示Neoverse N1平台和E1 CPU即将发布,Neoverse N1和E1采用7nm制程,并且为服务器和通信设备增加重要提升,拥有高可扩展性、高处理量以及高性能,将分别在2020年和2021年投入使用。

与Cortex-A72内核相比,N1分别将Java和memcacheD性能提高了1.7倍和2.5倍。与A72相比,N1内存延迟从110 ns降至83 ns,DRAM流量从64 GB /秒上升至175 GB / s。ARM认为,通过 Neoverse N1平台,Arm 除了提升60%整数运算性能,关键云计算作业负载性能也提高2.5倍。

%title插图%num

虽然ARM给出了Neoverse N1平台和E1 CPU的出色数据,但是Linus Torvalds认为当开发者在云端部署应用时他们会尽可能选择与他们工作环境相同的系统,匹配测试的本地设置,而他们的工作环境基本上是 x86服务器。对x86的偏爱将会影响到云服务商的决策,x86将会更受重视。

去年10月,ARM发布了Neoverse。ARM服务器Neoverse SoC***的客户包括Amazon、HPE、华为等。

其中,AWS去年12月开始了提供基于ARM A72内核的Amazon Graviton的云端处理器,被外界认为是开始淡化英特尔Xeon服务器处理器依赖的***步。2015年,AWS收购Annapurna Labs,开始着手构建自己的服务器CPU。

有人驳斥了Linus Torvalds,认为Linus 不甚了解交叉开发对大多数开发者的意义,而这恰好是ARM的长处。Linus Torvalds则表示,兼容ARM架构的处理器永远不会成为市场的主宰,并用“如果每个人都采用交叉开发的模式,那么必将影响产品的稳定性”这个论据以支撑自己的观点。

%title插图%num

Redis之父Salvatore Sanfilippo也不赞同Linus Torvalds,他表示Redis正在考虑将ARM作为主要架构,Redis一些底层代码只能在ARM平台上运行,这些代码都通过了所有测试,并且稳定性很好。

的确,目前云服务提供商推出了云端ARM芯片很容易被人视为与英特尔议价的手段,因为英特尔占据了服务器芯片市场*大部分的份额。可以说ARM服务器的生态依然处于早期,要想在数据中心市场与X86服务器芯片角力,依然需要走很长的路。让我们拭目以待ARM服务器后续的真正表现。

ARM 开启Dcache 问题

ARM926EJS Dcache是依赖于MMU,只有开启MMU后Dcache 才真正有效。

正常情况下,开启 Dcache 可以大大加快 CPU 性能;但是遇到特殊情况则出现很大的问题。

有以下三种情况:

采用不可缓存代码;
采用自修改代码;
操作AHB总线。
采用不可缓存代码
与其他ARM9系列的缓存内核来比,尽管非缓存代码的性能得到了改善,仍然推荐采用ICache,这是实践证明了的。

非缓存代码通常用在boot loader上面,防止cache污染。但是现在ICache在没有启用MMU的情况下仍然能够使能,而且可以通过控制 cache lockdown register 来防止污染,所以采用非缓存代码是没有优点的。

采用自修改代码
采用一个四字的缓冲区来保存推测到的将要获取的取指令。只有连续的指令可以准确地获取,万一 ARM9EJ-S 内核,缓冲区的内容会被丢掉(discard/flush)。在内核连续预取指的序列中,预取缓冲区的内容可能变为无效,这种情况下,预取缓冲器也应该被刷新(flush)。

操作AHB总线
ss

为了保证数据和指令的一致性,必须做以下操作

1. Clean the DCache
2. Drain the write buffer
3. Synchronize data and instruction streams in level two AHB subsystems
4. Invalidate the ICache
5. Flush the prefetch buffer

代码如下:

clean_loop
MRC p15, 0, r15, c7, c10, 3 ; clean entire dcache using test and clean
BNE clean_loop
MCR p15, 0, r0, c7, c10, 4 ; drain write buffer
STR rx,[ry] ; nonbuffered store to signal L2 world to synchronize
MCR p15, 0, r0, c7, c5, 0 ; invalidate icache

c语言(iar):

<code>

__root unsigned int a_a=9;
#pragma optimize=none
void flush_cache(void)
{
CP15_TestCleanDcache();
CP15_DrainWriteBuffer();
a_a ++;
CP15_InvalidateIcache();
}
</code>

嵌入式系统的内存管理

嵌入式系统的内存管理

摘要:实时性、可靠性的要求,使得许多嵌入式应用使用自己的内存管理程序。本文探讨嵌入式系统中对内存管理的要求、存在的问题以及可能的解决策略;介绍一种“一次分配,多次使用”的动态内存分配方法,并给出2个例子。
关键词:嵌入式系统 内存管理 一次分配多次使用
1 嵌入式系统中对内存分配的要求
①快速性。嵌入式系统中对实时性的保证,要求内存分配过程要尽可能地快。因此在嵌入式系统中,不可能采用通用操作系统中复杂而完善的内存分配策略,一般都采用简单、快速的内存分配方案。当然,对实性要求的程序不同,分配方案也有所不同。例如,VxWorks采用简单的*先匹配如立即聚合方法;VRTX中采用多个固定尺寸的binning方案。
②可靠性。也就是内存分配的请求必须得到满足,如果分配失败可能会带来灾难性的后果。嵌入式系统应用的环境千变万化,其中有一些是对可靠性要求*高的。比如,汽车的自动驾驶系统中,系统检测到即将撞车,如果因为内存分配失败而不能相应的操作,就会发生车毁人亡的事故,这是不能容忍的。
③高效性。内存分配要尽可能地少浪费。不可能为了保证满足所有的内存分配请求而将内存配置得无限大。一方面,嵌入式系统对成本的要求使得内存在其中只是一种很有限的资源;另一方面,即使不考虑成本的因素,系统有限的空间和有限的板面积决定了可配置的内存容量是很限的。
2 静态分配与动态分配 究竟应用使用静态分配还是动态分配,一直是嵌入式系统设计中一个争论不休的总是。当然,*合适的答案是对于不同的系统采用不同的方案。如果是系统对于实时性和可靠性的要求*高(硬实时系统),不能容忍一点延时或者一次分配失败,当然需要采用静态分配方案,也就是在程序编译时所需要的内存都已经分配好了。例如,火星探测器上面的嵌入式系统就必须采用静态分配的方案。另外,WindRiver公司的一款专门用于汽车电子和工业自动化领域的实时操作系统OSEKWorks中就不支持内存的动态分配。在这样的应用场合,成本不支持内存的动态分配。在这样的应用场合,成本不是优先考虑的对象,实时性和可靠性才是必须保证的。当然,采用静态分配一个不可避免的总是就是系统失去了灵活性,必须在设计阶段就预先知道所需要的内存并对之作出分配;必须在设计阶段就预先考虑到所有可能的情况,因为一旦出现没有考虑到的情况,系统就无法处理。这样的分配方案必须导致很大的浪费,因为内存分配必须按照*坏情况进行*大的配置,而实际上在运行中可能使用的只是其中的一小部分;而且在硬件平台不变的情况下,不可能灵活地为系统添加功能,从而使得系统的升级变得困难。 大多数的系统是硬实时系统和软实时系统的综合。也就是说,系统中的一部分任务有严格的时限要求,而另一部分只是要求完成得越快越好。按照RMS(Rate Monotoin Scheduling)理论,这样的系统必须采用抢先式任务调度;而在这样的系统中,就可以采用动态内存分配来满足那一部分可靠性和实时性要求不那么高的任务。采用动态内存分配的好处就是给设计者很大的灵活性,可以方便地将原来运行于非嵌入式操作系统的程序移植到嵌入式系统中,比如,许多嵌入式系统中使用的网络协议栈。如果必须采用静态内存分配,移植这样的协议栈就会困难得多。另外,采用动态内存分配可以使设计者在不改变基本的硬件平台的情况下,比较灵活地调整系统的功能,在系统中各个功能之间作出权衡。例如,可以在支持的VLAN数和支持的路由条目数之间作出调整,或者不同的版本支持不同的协议。说到底,动态内存分配给了嵌入式系统的程序设计者在比较少的限制和较大的自由。因此,大多数实时操作系统提供了动态内存分配接口,例如malloc和free函数。
3 RTOS提供的内存分配接口 不同的RTOS由于其不同的定位,采用不同的内存分配策略。
例如VRTX中,采用类似于GNU C中由Doug Lea开发的内存分配方案,即Binning算法,系统内存被分成了一些固定尺寸的内存块的算法,系统内存被分成了一些固定尺寸的内存块的集合。这种方法的优点是查找速度快而且不会产生内存碎片。但是,它的缺点也很明显,就是容易造成浪费,因为内存块的尺寸只有有限个,分配时只能取较大的内存块来满足一个较小的需求,累积起来,浪费就很大了;而且操作系统管理这样一个内存分配表也是一个很大的负担。 下面详细介绍一下我们常用的RTOS——美国风河公司(WindRiver)的VxWorks中采用的内存分配策略。VxWorks的前身就是VRTX,据说VxWorks的名称来自make vrtx work。 VxWorks的内存管理函数存在于2个库中;memPartLib(紧凑的内存分区管理器)和memLib(完整的内存分区管理器)。前者(memPartLib)提供的工具用于从内存分区中分配内存块。该库包含两类程序,一类是通用工具创建和管理内存分区并从这些分区中分配和管理内存块;另一类是标准的malloc/free程序提供与内存分区的接口。系统内存分区(其ID为memSysPartId是一个全局变量)在内核初始化时由usrRoot调用memInit创建。其开始地址为RAM中紧接着VxWorks的BSS段之后,大小为所有空闲内存,如图1所示。 当创建其它分区时,一般需要先调用malloc从系统内存分区中分配一段内存才能创建。内存分区的结构定义为mem_part,包含1个对象标记,1个双向链表管理空闲块,1个信号量保护该分区及一些统计信息,如总尺寸、*大块尺寸、调试选项、已分配的块数、已分配的尺寸等。其语句如下:
typedef struct mem_part
{ OBJ_CORE objCore; /*对象标志*/
DL-LIST freeList; /*空闲链表*/
SEMAPHORE sem; /*保护分区的信号量*/
Unsigned totalWords; /*分区中字(WORD)数*/
Unsigned minBlockWords; /*以字为单位的*小块尺寸*/
Unsigned options; /*选项,用于调试或统计*/ /*分配统计*/
unsigned curBlocksAllocated; /*当前分配的块数*/
unsigned curWorkdAllocated; /*当前分配的字数*/
unsigned cumBlockAllocated; /*累积分配的块数*/
unsigned cumWordsAllocated; /*累积分配的字数*/
}PARTITION;
一般系统中只有1个内存分区,即系统分区,所有任务所需要的内存直接调用malloc从其中分配。分配采用First-Fit算法(注意这种算法容易导致大量碎片),通过free释放的内存将被聚合以形成更大的空闲块。这就是VxWorks的内存分配机理。分配时可以要求一定的对齐格式。注意,不同的CPU架构有不同的对齐要求。为了优化性能,malloc返回的指针是经过对齐的,为此的开销随构不同而不同。例如,68K为4字节对齐,开销8字节;SPARC为8字节对齐,开销12字节;MIPS为16字节对齐,开销12字节;I960为16字节对齐,开销16字节。 MemLib库中提供了增强的内存分区管理工具,并且增加了一些接口,而且可以设置调试选项。可以检测2类错误:①尝试分配太大的内存;②释放内存时发现坏块。有4种错误处理选项,当发生错误时记录消息或挂起任务。 但是,使用动态内存分配malloc/free时要注意到以下几方面的限制。①因为系统内存分区是一种临界资源,由信号量保护,使用malloc会导致当前调用挂起,因此它不能用于中断服务程序;②因为进行内存分配需要执行查找算法,其执行时间与系统当前的内存使用情况相关,是不确定的,因此对于有规定时限的操作它是不适宜的;③由于采用简单的*先匹配算法,容易导致系统中存在大量的内存碎片,降低内存使用效率和系统性能。 针对这种情况,一般在系统设计时采用静态分配与动态分配相结合的方法。也就是对于重要的应用,在系统初始化时分配好所需要的内存。在系统运行过程中不再进行内存的分配/释放,这样就避免了因内存的分配释放带来的总是。而且在系统初始化,因为没有内存碎片,对于大的内存块的需求容易满足。对于其它的应用,在运行时进行动态内存分配。尤其是某些应用所要求的大量固定尺寸的小内存块,这时就可以采用一次分配多次使用的内存分配方案。下面详细介绍这种内存分配方案及其应用场合。
4 一次分配多次使用的内存分配方案 在嵌入式系统设计中,经常有一些类似于内存数据库的应用。这些应用的特点是在内存中管理一些树,比如以太网交换机中的MAC地址表、VLAN表等,或者路由器中的路由表。这些树是由许多相同尺寸的节点组成的。这样,就可以每次分配一个大的缓冲池,比如包含多个内存单元的数组,每个内存单元用于1个节点。我们用一个空闲链表来管理该数组中的空闲内存单元。每次程序需要分配内存以创建1个新的节点时,就从空闲链表中取1个单元给调用者。程序删除节点并释放内存时,将释放的内存单元返还给空闲链表。如果链表中的空闲内存单元取空了,就再次调用malloc从系统内存中分配一个大的内存块作为新的缓冲池。采用这样一种方案主要有如下优点:①减少了malloc/free的调用次数,从而降低了风险,减少了碎片;②因为从缓冲池中取一个内存单元是时间确定的(当然,如果缓冲池耗尽从而需要重新调用malloc分配除外),因此它可以用于严格时限的场合从而保证实时性;③它给用户以自由来添加一些用于内存分配和释放的调试函数以及一些统计功能,更好地监测系统中内存的使用情况。 这种方案必然涉及到一个缓冲池的结构。一般缓冲池的结构由以下几部分组成:单元尺寸、块尺寸(或者单元数目)、缓冲池指针、空闲链表、用于统计和调试的参数等。对缓冲池的操作包括创建缓冲池、释放缓冲池、从缓冲池中分配1个内存单元、释放内存单元回缓冲池等。下面举2个例子说明一下该方案的具体使用情况。
4.1 Intel交换机驱动程序中内存分配 在以Intel的交换芯片为基础的交换机方案中,因为采用的是软件地址学习的方式,需要在内存中维护许多数据,如MAC地址表的软拷贝、VLAN表、静态单播地址表、组播地址表等。这些表都是由一些树组成,每个树由一些固定尺寸的节点组成。一般每个节点几十个字节,每棵树的节点数是可增长的,少则几十,*多可到16K个节点。因此,很适合于采用该方案,具体的实现如下:
(1)缓冲池结构BlockMemMgr typedef struct{ MemSize data_cell_size; /*数据单元的尺寸*/ MemSize block_size; /*块尺寸*/ /*下面的变量为预定义的每个管理器*多包含的块数,如64 MAX_BLOCKS_OF_MEM_SIZE*/ Unsigned short blocks_being_used;/*已使用的块数*/ Void mem_ptr[PAX_BLOCKS_OF_MEM_SIZE]; /*块数组*/ SLList free_data_cells_list; /*空闲链表*/ }BlockMemMgr; 结构中的参数包括:单元尺寸、块尺寸、已用块数、所有块的地址、空闲链表(单向链表)。
(2)缓冲池的管理函数
◆block_mem_create:创建块内存管理器,参数包括内存指针(如为NULL,表示自己分配)、块尺寸、单元尺寸、返回管理器指针。 过程如下: ①检验参数合法性。 ②单元尺寸4字节对齐,计算每个块中的单元数。对内存指针进行4字节对齐或者分配内存指针。 ③初始化结构BlockMemMgr,包括单元尺寸和块尺寸。设置第1个内存块的指针。如果内存是外来的,设置块已用标志(已用为0),表示不能增加块;否则,已用块数设为1。 ④创建空闲链表,将块内所有单元添加到链表中,*后一个单元处于链表的*前面。 ⑤返回BlockMemMgr。
◆block_mem_destroy:解构一个块内存管理器,释放它所分配的所有内存,调用者负责外部内存的释放。参数为BlockMemMgr。返回成功失败标志。 ①参数合法性检测。 ②删除单向链表(设链表指针为NULL)。 ③如果块是动态分配的,释放它们。 ④释放结构BlockMemMgr。
◆block_malloc:从块内存管理器中分配1个单元。参数为BlockMemMgr,返回数据单元指针。 ①参数合法性检测。 ②判断空闲链表是否为空(是否为NULL)。如果为空,判断是否可以动态分配块,如果不能,返回失败;如果可以动态分配块,则分配1个块,执行与block_mem_create一样的操作。 ③从空闲链表中分配第1个单元,返回其指针。 注意这里有一个小技巧,即数据单元在空闲时其中存放空闲链表的节点信息,而分配后则存放数据内容。
◆block_free:释放1个数据单元,返回块内存管理器。小心不要对1个单元释放2次。参数为BlockMemMgr和单元指针。 ①参数合法性检测。 ②地址比较,判断数据单元属于哪个块。 ③判断数据单元的内容是否为空闲链表节点信息(也就是块内某单元的地址),从而确定是否为2次释放。 ④将该数据单元插入到空闲链表的前面。 ⑤引用该单元的指针设为NULL。
内存管理代码遵守如下约定:①管理的内存是实际可写的内存;②分配内存是4字节或32位对齐;③block_malloc、block_free在中断级调用是部分安全的,除非BLOCK中已经没有空闲CELL,需要重新调用malloc分配新的BLOCK(而malloc和free就不是安全的,因为其中使用了信号量和搜索算法,容易引起中断服务程序阻塞)。当然,block_mem_create和block_mem_destroy必须在进程级调用。 4.2 TMS中的内存分配 TMS是WindRiver公司为可管理式交换机推出的开发包。它用用IDB来管理各种协议的数据,比如STP和GVRP等。为了支持IDB,它建立了自己的缓冲池管理方案,程序在bufPoolLib.c中。该程序包含用于缓冲池管理的函数,这些函数允许从1个池中分配固定数目和大小的缓冲区。通过预先分配一定数目固定大小的缓冲区,避免了反复的小的内存块分配/释放相关联的内存碎片和浪费。既然它从1个单一的块中分配缓冲池,也比对每一个缓冲区执行1次分配有更高的空间效率。模块对每个缓冲区加上1个标记(MAGIC),释放时会检查标记。模块给用户提供分配和释放操作定义回调函数的能力。这样可以做到自动的对象创建和解构,同时允许由多个缓冲池分配的成员组成的对象做为1个单一的实体删除。这类似于C++中自动的对象构建和解构,不过是用C语言并且没有堆栈分配的负担。模块既允许从堆栈中分配缓冲池(通过calloc),也可以在用户分配的空间中创建它们。模块用1个单向链表来维护未分配的缓冲区,但不跟踪已分配的缓冲区。模块并不是任务安全的,用户需要用信号时来保护缓冲池。
(1)缓冲池结构
typedef struct
{ ulong_t magic; /*用于一致性检测的特殊标记*/
Boolean localAlloc; /*内存是否在创建缓冲区时分配*/
SL_LIST freeList; /*空闲链表*/
Void store; /*缓冲区指向的内存指针*/
STATUS(*createFn)(void*,ulong_t argl); /*创建缓冲区时的回调函数指针*/
STATUS(*destroyFn)(void*,ulong_targl);/*释放缓冲区时的回调函数指针*/
Ulong_t argVal;/*回调函数的参数*/
} buf_pool_t;
结构中的参数包括检查标记MAGIC、是否本地分配、空闲链表、内存指针、创建缓冲池的回调函数指针、释放时的回调函数指针、回调函数参数。
(2)相关函数
◆BufPoolInitializeStorage:分配和初始化存储区。参数包括存储区地址(如为NULL,则本地分配)、缓冲区大小、缓冲区个数。 ①根据缓冲区大小和个数获得所需的内存大小。 ②如果指针为NULL,则调用calloc分配内存。设置本地分配标志。 ③初始化内存为0。 ④初始化指针。分配的内存块*前面为缓冲池结构buf_pool_t。实际的存储区紧随其后。Buf_pool_t包含参数检查标记、是否本地分配、存储区地址、分配时回调函数、释放时回调函数、回调函数变量。此时只设置存储区指针。
◆BufPoolCreate:创建缓冲池。参数为内存制止。缓冲区尺寸和个数,创建时回调函数、释放时回调函数、回调函数参数。 ①尺寸对齐。 ②调用bufPoolInitializeStorage初始化内存区和buf_pool_t结构。 ③用传入参数填充buf_pool_t结构。 ④将缓冲区添加到空闲链表中,*后的缓冲区在*前面。
◆BufPoolDestroy:删除缓冲池。参数为buf_pool_t指针。 ①检查缓冲池结构中的MAGIC字段是否被个性。 ②如果是本地分配的则翻放内存区。
◆BufPoolAlloc:从缓冲池中分配一个缓冲区,参数为缓冲池结构指针。如果存在空闲缓冲区,则从空闲链表中除并提供给调用者,执行创建时回调函数。如果回调函数返回错误,则将缓冲区返还给空闲链表。 ①检查缓冲池结构中的MAGIC标记是否完好。 ②从空闲链表中取出头一个节点。 ③如果节点不为空,清空节点,以其地址为参数调用回调函数。 ④如果回调函数返回错误,则将节点还给空闲链表。 ⑤返回得到空闲缓冲区地址。
◆BufPoolFree:将缓冲区返回给缓冲池。如果定义了回调函数,将在归还缓冲之间调用回调函数。参数为缓冲池结构和缓冲区指针。 ①缓冲池MAGIC标记是否完好。 ②如果定义回调函数、调用之。如果返回错误,则设置错误号。 ③将缓冲区添加到空闲链表中头部。 注意该函数有2点:①回调函数返回错误,照样归还缓冲区。②没有检查缓冲区是否二次释放,这一点与Intel的驱动程序不同。 另外,TMS的缓冲池没有BLOCK要领,不需要判断哪个CELL属于哪个BLOCK,简化 了操作。 5 小结 许多嵌入式应用在RTOS提供的malloc/free的基础上编写自己的内存管理方案。编写这样的内存管理方案,目的无非有两个:一是减少对malloc/free的依赖,从而避免由之带来的内存碎片、时间不确定等总是;另一个是增强程序的查错能力,送还内存使用错误。对于在嵌入式系统中广泛存在的数据库类型的内存需求,即分配多个固定尺寸的内存单元的要求,“一闪分配,多次使用”的方案无疑是一种很好的解决之道。文中介绍的2个例子很好地体现了它的优越性。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速