-
零基础参加web前端开发培训后有好就业吗?
参加web前端开发培训前途好吗?这是很多想参加培训机构的人关心的话题,毕竟现在培训机构众多,参加培训的人也是前仆后继的,这么多人都去参加培训了,那么出来还好找工作就业吗?零基础参加web前端开发培训后有好就业吗?虽然现在很多人都在参加web前端开发培训,但有两点需要大家注意:1、培训机构资质如今的培训市场鱼龙混杂,很多资质不符合的机构也大肆招收学员入学培训。然而这样的机构聘请的老师没有丰富的经验,连自己都能力欠缺,怎么能教出来好学生?而且学校没有满足市场需求随时更新的教学课程,就算学会了,也是一些老旧的技术,这样是不具备市场竞争力的。2、培训机构就业如今培训机构的广告天花乱坠,每一家的广告都打得响亮,目的就是为了吸引更多的学员报名,然而却没有把钱放在请老师,更新课程,及就业的保障上面。没有学到扎实的技术,就很难就业,而且很多学校也对就业没有足够的资源。
-
移动开发之手势与双指缩放
当年乔布斯的iphone第一次支持多点触控时,确实惊艳了世人,而现在大部分手机都支持多点触控,这就有了手势这个概念,通过多点触控,形成不同的手势,开发者根据不同手势,提供不同功能,比如双指缩放,是很常见的。ios的多点触摸ios的Safari浏览器是第一个支持多点触摸的浏览器,并提供触摸API供开发者使用,到后来Android3也开始支持多点触摸,各大浏览器也借鉴Safari提出了触摸API,除了个别硬件支持属性外,大致相同,这是值得庆幸的。IE10的多点触摸虽然现在市场上WP手机越来越少,但是为了更完整的学习理解手势知识,我们也需要进行学习。IE10支持多点触摸,但是其多点触摸与ios和android不同,ios和android浏览器为多点触摸提供一个包含touches数组的事件,包含所有多点触摸对象,而IE10为多点触摸的每一个触摸点创建一个单独的触摸事件。渐进增强与手势我们知道手势很方便,用户也很喜欢手势,但是我们也要明白手势并不总是能使用,有些设备或浏览器还是不支持的,所以我们最合适的是基于普通点击和触摸事件交互的页面,将手势作为增强的交互,这就是通常所说的渐进增强思想。触摸事件既然是要渐进增强,那就必须从基础点击和触摸事件说起,点击事件就不再多说,关于触摸事件,之前也有一篇文章介绍过移动开发之轻触与单击事件,关于触摸四种基础事件和事件对象,可以查看该文章,这里就不重复了,这里要对触摸事件的处理进行说明。浏览器兼容通常我们在触摸和手势事件处理函数内会添加CSS3动画处理,这个时候需要进行浏览器兼容处理。varTRANSITION='transition';varTRANSITION_END='transitionend';varTRANSFORM='transform';varTRANSFORM_PROPERTY='transform';varTRANSITION_PROPERTY='transition';if(typeofdocument.body.style.webkitTransform!==undefined){TRANSFORM='webkitTransform';TRANSITION='webkitTransition';TRANSITION_END='webkitTransitionEnd';TRANSFORM_PROPERTY='-webkit-transform';TRANSITION_PROPERTY='-webkit-transition';}双指缩放在移动端手势事件中,双指缩放的需求还是很常见的,本节详细阐述,现在大多数移动设备都支持原生的双指缩放,但是这样可能影响页面布局,而且为了更多可控性,很多时候还是会选择自行实现缩放手势功能。缩放中心在原生缩放动画,缩放中心通常是图像中心,可以拿起移动设备尝试一番,而在现实需求中,我们通常希望缩放以手势屏幕的两个接触点中心为中心,即缩放中心为接触点中心。变换原点在CSS3动画中,如,transform动画旋转,缩放等动画,有一个transform-origin属性:Thetransform-originpropertyletsyoumodifytheoriginfortransformationsofanelement.transform-origin属性使得我们可以修改一个元素变换动画的原点。当我们使用CSS3变换动画进行缩放时,由于变换动画的变换原点和缩放中心(即接触点中心)相互独立,为了不影响缩放中心相对于元素的位置,元素变换缩放时,也应该对缩放中心坐标进行缩放移动,即除了变换缩放元素,还应该对该元素进行额外坐标偏移。位移偏量我们希望缩放以接触点中心为中心,元素向四周缩放,假设变换原点为元素左上角,即transform-origin:00;,此时元素变换缩放位移均为正值,仅向右下方向缩放,所以缩放中心(其实也就是该元素)应对应向相反方向(左上方向)偏移,值为缩放坐标值*(1-缩放比例)。如上图,原始元素A盒,以接触点M,N两点的中心点L(x,y)为缩放中心点,向四周缩放,其位置应该如图中C盒,由于L(x,y)点的位置是不可控的(用户行为),我们设置元素变换原点transform-origin:00;,此时其缩放后位置如B盒,然而我们依然希望达到缩放后形成C盒的位移效果,则我们需要将元素向左上方向位移,假设缩放比例为k,则元素位移值计算过程如下:1.计算元素A的位移,其实等效于缩放点的位移,也就是计算坐标系缩放后进行的位移;2.L(x,y)点,在缩放前坐标系中坐标为(x,y),则缩放k倍后,其在缩放后坐标系中坐标为(kx,ky);3.计算两点位移距离:水平位移:x–kx;垂直位移:y–ky;4.得到元素在水平和垂直方向需要偏移的距离。缩放的实现禁止原生缩放要使用自行实现的缩放手势,我们需要首先禁止元素缩放手势,使用user-scalable=no:缩放与滚动我们自行实现的缩放事件需要使用touchmove事件,而touchmove事件会触发设备的滚动事件,所以要么阻止滚动,要么不让屏幕出现滚动条。阻止滚动document.addEventListener('touchmove',function(event){event.preventDefault();})阻止滚动条html,body{height:100%;}计算缩放中心缩放动画以接触点为中心,当我们使用双指手势实现缩放时,这个接触点中心就是两个接触点的中心点:functiongetOrigin(first,second){return{x:(first.x+second.x)/2,y:(first.y+second.y)/2};}getOrigin({x:event.touches[0].pageX,y:event.touches[0].pageY},{x:event.touches[1].pageX,y:event.touches[1].pageY});计算缩放比例缩放比例如何确定呢,起始触摸两指间距离除以缩放时两指间距离,即缩放比例:functiongetDistance(start,stop){returnMath.sqrt(Math.pow((stop.x-start.x),2)+Math.pow((stop.y-start.y),2));}functiongetScale(start,stop){returngetDistance(start[0],start[1])/getDistance(stop[0],stop[1]);}处理触摸事件要实现缩放功能除了计算相关缩放中心和缩放比例,另外还需要处理触摸事件:vardistance={};varorigin;varscale=1;functionhandleTouch(e){switch(e.type){case'touchstart':if(e.touches.length>1){distance.start=getDistance({x:e.touches[0].screenX,y:e.touches[0].screenY},{x:e.touches[1].screenX,y:e.touches[1].screenY});}break;case'touchmove':if(e.touches.length===2){origin=getOrigin({x:event.touches[0].pageX,y:event.touches[0].pageY},{x:event.touches[1].pageX,y:event.touches[1].pageY});distance.stop=getDistance({x:e.touches[0].screenX,y:e.touches[0].screenY},{x:e.touches[1].screenX,y:e.touches[1].screenY});scale=distance.stop/distance.start;setScaleAnimation(scale,true);}break;case'touchend':scale=1;setScaleAnimation(scale);break;case'touchcancel':scale=1;setScaleAnimation(scale);break;default:;}}使用变换接下来就是使用CSS3动画缩放图片了,代码如下:functionsetScaleAnimation(scale,animation){vartransition_animation='';varx,y;if(animation){transition_animation='none';}else{transition_animation=TRANSFORM_PROPERTY+'0.3sease-out';}element.style[TRANSITION]=transition_animation;//计算位移偏量x=origin.x+(-origin.x)*scale;//缩放中心偏移量y=origin.y+(-origin.y)*scale;//缩放和位移element.style[TRANSFORM]='matrix('+scale+',0,0,'+scale+','+x+','+y+')';}点此查看双指缩放实例本文所有实例代码点此查看本文关于移动开发手势及实现双指缩放介绍到此完结,实现的实例比较粗糙,但原理基本阐述清楚,感兴趣可以自己动手实现,优化;本文很久以前就开篇了,但直到今天才终于完笔,若有不足,也欢迎指正。
-
WEB前端开发培训需要掌握哪些技能
随着互联网的迅猛发展和普及,一个新型的行业和新兴的职位正在上升到技术层面:web前端开发工程师,Web前端开发工程师,除了主要职责外,还要为网站上提供的产品和服务实现一流的Web界面,优化代码并保持良好兼容性。那么WEB前端开发培训都需要做什么?该掌握哪些技能呢?WEB前端开发培训需要掌握哪些技能1、web前端开发工程师-web2.0时代2、Web前端表现层及与前后端交互的架构设计和开发3、配合后台开发人员实现产品界面和功能4、利用各种Web技术模拟开发产品原型5、Web新技术调研和资讯整理6、精通HTML/XHTML、CSS,熟悉页面架构和布局,对Web标准和标签语义化有深入理解7、熟悉Ajax、Java(或者Action)、DOM等前端技术,掌握面向对象编程思想。除了要做上面几个工作内容以外,还要求web开发工程师对常用的一些JS框架了解,如jQuery、YUI等。掌握基本的Java计算方法编写。对目前互联网流行的网页制作方法(Web2.0)HTML+CSS,以及各大浏览器兼容性有很大的了解。对前沿技术(HTML5+CSS3)的基本掌握。还要对IT其他编程语言有所了解如:PHP,Java,.net!有一些公司还要求懂一点SEO优化!
-
一些关于移动开发的自我看法
如今移动应用的火热程度不用我多说,相信大家都有切身感受。硬件的快速升级,更是加速了各种应用的涌现,功能越来越强大,效果越来越绚丽。电脑上的应用正在往移动设备上转移。比如现在的手机已经不在只是通讯设备,而是演变成了具有娱乐,办公等功能的综合性设备。移动设备的进一步快速普及,毫无疑问的会增加移动应用的需求,说移动开发是目前最火的领域之一一点不为过。但是要开发一款好的应用却不是一件容易的事,对于"好"的理解每个人或许都有不同的理解,作为一名移动相关开发人员,我对好的理解是:简单+实用+漂亮的UI设计。并非功能多就能吸引人,首先得漂亮,让人愿意看才行,其次是要易于操作,要让用户快速掌握对你这个应用的使用,不能是半天都找不见功能在哪儿,再有就是简单,操作简单以及功能简单,要让用户用尽可能少的步骤开启某功能,如果是面向大众的,功能上选取普通用户常用的即可。移动设备便于携带,同时也伴随着另一个问题就是安全性。所以如何保护用户数据的安全是必须要考虑的问题。现在的云技术提供了一种方案,移动+云技术似乎已经成为现在主流的移动开发模式。社会的发展很快,移动开发也不会一直热下去,借用一位前辈的话说"现在将过去pc上的应用拿到手机上,未来会将手机上的应用移植到web上",相信这个未来不会太久。
-
移动开发与云服务
1、移动开发日渐崛起超过50%的受访者打算在2012年投入更多的精力在移动开发方面,而相比2010年该数值只有27.4%。a、iOS.Apple的操作系统吸引了众多眼球,89%的开发人员表示他们对iPhone开发感兴趣,而且88%的开发人员对iPad开发感兴趣。b、Android.虽然Android一个季度内开发人员的兴趣点下降了4.7%,但是总的百分比依旧牢固在78.6%。c、WindowsPhone7.虽然WindowsPhone7销售量依然不高,但开发人员对微软的移动操作系统兴趣丝毫未减。WindowsPhone,AndroidiPhone移动开发阵营将三雄争霸2、云服务(CloudServices).开发人员对于移动应用程序中使用以下云服务感兴趣:35%的开发人员对位置服务(Location)感兴趣;33%的开发人员对通知服务(Notification)感兴趣;11%的开发人员对评分及评论服务(Rating&Reviews)感兴趣;8%的开发人员对图片服务(Photo)感兴趣;7%的开发人员对签到服务(Check-in)感兴趣;6%的开发人员对地点服务(Places)感兴趣。
-
Java并发编程--线程安全问题与解决方案
用多线程开发的人都知道,在多线程的开发过程中有可能会出现线程安全问题(专业术语叫内存可见性问题),但并不一定每次都会出现。出现这样的情况,也会另开发者头皮发麻,无从下手,接下来我们会慢慢深入,揭开多线程的神秘面纱。本文主要介绍了Java多线程开发的优势,使用该技术可能会出现的一些内存不可见问题以及相应的解决措施。通过本文,读者将学习到如下几块知识:为什么需要多线程技术(多线程的优势)使用多线程技术带来的一些问题产生内存不可见问题的条件产生内存不可见问题的原因我们该如何分析会不会产生内存可见问题及出现问题之后的解决方式下面进入正文为什么需要多线程技术(多线程的优势)线程是Java语言中不可或缺的重要部分,它们能使复杂的异步代码变得简单,简化复杂系统的开发;能充分发挥多处理器系统的强大计算能力。充分利用硬件资源。由于线程是CPU的基本调度单位,所以如果是单线程,那么最多只能同时在一个处理器上运行,意味着其他的CPU资源都将被浪费。而多线程可以同时在多个处理器上运行,只要各个线程间的通信设计正确,那么多线程将能充分利用处理器的资源。结构优雅。多线程程序能将代码量巨大,复杂的程序分成一个个简单的功能模块,每块实现复杂程序的一部分单一功能,这将会使得程序的建模,测试更加方便,结构更加清晰,更加优雅。简化异步处理。为了避免阻塞,单线程应用程序必须使用非阻塞I/O,这样的I/O复杂性远远高于同步I/O,并且容易出错。使用多线程技术带来的一些问题线程安全(内存可见性问题):由于统一进程下的多个线程是共享同样的地址空间和数据的,又由于线程执行顺序的不可预知性,一个线程可能会修改其他线程正在使用的变量,这一方面是给数据共享带来了便利;另一方面,如果处理不当,会产生脏读,幻读等问题,好在Java提供了一系列的同步机制来帮助解决这一问题,例如内置锁。活跃性问题。可能会发生长时间的等待锁,甚至是死锁。性能问题。线程的频繁调度切换会浪费资源,同步机制会导致内存缓冲区的数据无效,以及增加同步流量。产生内存不可见问题(线程安全问题)的条件产生内存不可见的条件有俩个1.多个线程2.存在共享变量当多个线程操作了共享变量时,就有可能会产生线程安全问题(内存不可见问题)。产生内存不可见问题的原因产生内存不可见的问题有三个原因1.没有保证代码的原子性2.没有保证代码的可见性3.没有保证代码的有序性1.1没有保证原子性产生内存不可见的究极原因?由于现代的CPU是多核的,可以实现并行,所以读书的时候我一直带着这样的疑问?多核会不会同时操作同一内存下的数据:举例代码i++;多核处理器会不会同时执行这行代码?答案是不会同时执行。请参考1.2没有保证代码的可见性产生内存不可见的究极原因?可见性定义:一个线程的写对另一个线程立即可知。现代的处理器都有读写缓冲区,读缓冲区异步从主存中读取数据,写缓冲区临时保存向内存写入的数据。有了写缓冲区可以保证指令流水线持续进行,它可以避免由于处理器停顿下来等待向内存写入数据而产生的延迟。同时以异步的方式刷新写缓冲区,以及合并写缓冲区中对同一个地址的多次写,减少对内存总线的占用。假设线程A,B,分别在俩个处理器上执行,初始时a=0,线程A先执行a=1,线程B再执行a=2,线程3去读变量a,最后a会是几呢?答案012都有可能。产生0的原因:线程A先执行a=1,然后放到写缓冲区,线程B再执行a=2,然后又放到写缓冲区,假设俩个写缓冲区还没又刷新的时候线程3去读变量a,此时线程3读取到变量a就为0。产生1的原因:线程A先执行a=1,然后放到写缓冲区,线程B再执行a=2,然后又放到写缓冲区,假设线程A所在处理器的写缓冲区已刷新,线程B还没又刷新的时候,线程3去读变量a,此时线程3读取到变量a就为1。产生2的原因:线程A先执行a=1,然后放到写缓冲区,线程B再执行a=2,然后又放到写缓冲区,假设线程B所在处理器的写缓冲区已刷新,线程A还没又刷新的时候,线程3去读变量a,此时线程3读取到变量a就为2。综上所诉,没有保证代码的可见性产生内存不可见的究极原因是:写缓冲区的存在,且以异步的方式刷新缓冲。1.3没有保证代码的有序性产生内存不可见的究极原因?编译器和处理器为了优化程序的性能会进行从排序,所以有序性会产生内存不可见问题。我们该如何分析会不会产生内存可见问题及出现问题之后的解决方式如何分析我们的代码会不会产生内存可见性问题Java虚拟机提供了Java内存模型来分析会不会产生内存可见性问题,Java内存模型也提供了一系列规则(happens-before等等)来辅助程序员更好的分析会不会产生内存可见行问题。出现问题之后的解决方式产生线程安全问题的原因有三个,解决方式无非就是1.保证代码的原子性2.保证代码的可见性3.保证代码的有序性。JVM提供了synchronized和volatile关键字来解决问线程安全问题Synchronized可以保证代码的原子性、保证代码的可见性、保证代码的有序性。volatile可以保证代码的可见性、保证代码的有序性但不能保证代码的原子性。所以Synchronized可以完全解决线程安全问题,而volatile不可以。总结为什么本篇要这么写呢?因为读完Java并发编程书籍之后,我觉得非常的混乱,读完之后感觉没有收获,就想写点东西做个总结,可是又无从下手,不知道如何引入到Java内存模型和synchronized、volatile关键字。为什么无从下手呢,后来发现是对Java内存模型和synchronized、volatile理解不够到位。Java内存模型可以帮助我们理解我们的代码会不会存在内存可见性问题。synchronized、volatile可以帮助我们解决内存可见性问题。前者是分析会不会产生问题,后者是产生问题之后的解决。既然理清了俩者的区别,那么该如何过渡到这呢,LZ想从本篇引入到并发学习中。
-
告诉你什么才是移动开发
一、简介移动开发也称为手机开发,或叫做移动互联网开发。是指以手机、PDA、UMPC等便携终端为基础,进行相应的开发工作,由于这些随身设备基本都采用无线上网的方式,因此,业内也称作为无线开发。移动应用开发是为小型、无线计算设备编写软件的流程和程序的集合,像智能手机或者平板电脑。移动应用开发类似于Web应用开发,起源于更为传统的软件开发。但关键的不同在于移动应用通常利用一个具体移动设备提供的独特性能编写软件。例如,利用iPhone的加速器编写游戏应用。3G时代,手机为王3G时代的到来,使得手机应用日渐热门,由于手机携带方便,并且是生活必带随身用品,而且信号覆盖广,操作便捷,使得人们对其给予了越来越高的期望。大家期待各种常见的或是重要的信息化系统、互联网应用可以被移植到手机上同步使用,使用户无论在何时何地,都可以连线精彩的网络世界,登录信息系统。为此,如何进行手机开发,如何在手机上催生各种多姿多彩的精彩应用,日渐成为整个ICT产业关注的焦点。二、开发难题1、手机操作系统很多:Android,Windowsphone7,Windowsphone8,iOS,SymbianS60,UIQ,WindowsMobile,Linux,Brew、Blackberry……,要想克服不同手机平台的差异,实现应用的统一覆盖异常困难;2、手机开发很难:开发人员稀缺,成本太高,进度太慢,无线网络太复杂,门槛障碍太多……;3、软件或互联网公司如果为了实现移动应用,而把精力投入到并非自己所长的领域,无疑将会得不偿失。4、行业需要专业的角色,来解决开发应用过程中的各种难题,将复杂难题封装简单,把各种异构封装透明,降低大家进入这个市场的门槛。三、移动开发工具PhoneGap一个HTML5应用程序平台,可以让你编写本机应用程序与Web技术,并获得API和应用程序商店。SenchaTouch这是一个高性能的HTML5移动应用框架,用于iPhone,Android和黑莓。iOS/Android用于创建iOS和Android应用程序,起源C#和NET。Appcelerator混合动力汽车和移动Web应用程序从一个单一的代码库开发一个软件开发工具包(SDK)。AdobeAIR建立一个框架,以苹果iOS,谷歌Android,黑莓TabletOS平台上运行的应用程序。ComponentOne在移动开发中,需要控件的支持,比如表格控件,label控件,textbox控件等等.可以创建两种类型的移动控件,即移动用户控件和自定义移动控件。用户控件是使用.ascx文件创建的,且继承自MobileUserControl。自定义移动控件是从System.Web.UI.MobileControls.MobileControl继承的独立对象。通过创建ASP.NET移动用户控件和自定义移动控件.ComponentOne第三方控件为移动开发提供各种UI控件,比如数据显示、文本编辑、布局控制、导航操作等.
-
一些你不知道的移动端开发技巧
最近接手了一个移动端的项目。个人感觉是自己做得比较快而且比较健壮的一个。。。移动端最主要就是页面要适用不同的手机屏幕,ipad等。下面就分享一些技巧,让你不依赖任何框架高效地搭建自己的项目。一、样式按组件或板块分文件写再合成①设置各种变量采用scss或者less来写css代码有很多好处。这里就不详细说。我们拿到设计图的第一步,就是要分析各个页面之间有哪些模块、哪些样式、哪些颜色是一样的。一般情况下,为了各个页面的风格统一,各个页面上的主颜色应该都是一致的,而且好些页面都会用到一些相同的组件,例如slider。所以,我们首先可以定义一个常量文件,里面就专门存放颜色、高度、宽度等变量。定义一个公共样式文件,例如写一些各个页面都有可能用到的清楚浮动等样式。个人感觉scss比less更好用一点,用scss定义的话,其中有一个方法是%定义法,就是定义了并不会被编译,而是实际上用到的时候才会被编译。例子图:②按模块细分个人感觉,按模块等细分之后,代码的可读性能够明显地提高,方便维护,而且引入页面的文件个数也减少了,还可以提高性能呢。不过,这里要注意,子模块的文件名要以“_”开始哦,这样就不会被编译,而是需要引用的时候再编译哦。例子如图:二、页面适应性布局个人认为,适配移动端比较好的布局方式是百分比+rem布局。百分比的优势在于,同一个百分比的真实尺寸会跟随屏幕大小变化。举个例子,像这种:红色框那里,假设现在的要求是一行4个板块,适应任何屏幕。那么,用ul,li写html,然后布局的话,如果写定ul的宽度是100%,然后li的宽度是25%,再设置box-sizing:border-box的话。各种屏幕下,这四块都是平分并且不会出现横向滚动条的。不过要注意,这个时候的间距就不要用margin-left和margin-right来撑开,而是用padding来撑开。就是像这样比例明显,板块区分度高的情况适合用百分比来布局。代码如下:ul{width:100%;margin-bottom:10px;}ulli{width:25%;box-sizing:border-box;}为什么要设置box-sizing:border-box;呢?不明白的话,可以看这里:http://www.w3school.com.cn/cssref/pr_box-sizing.asp。rem的话,rem的取值是只。相对于根元素htm的font-size,即只需要设置根元素的font-size,其它元素使用rem单位设置成相应的百分比即可。你再用@media写一下不同尺寸下跟元素html的font-size的值即可。然后神奇的事情就发生了。当你改变尺寸时,字体。图片等,就会自动跟着适应了。用起来真的很爽!一些常用的适应尺寸如下:@charset"utf-8";@mediaonlyscreenand(max-width:315px){html{font-size:50%!important;}}@mediaonlyscreenand(min-width:316px){html{font-size:62.5%!important;}}@mediaonlyscreenand(min-width:640px){html{font-size:125%!important;}}@mediaonlyscreenand(min-width:750px){html{font-size:150%!important;}}@mediaonlyscreenand(min-width:1242px){html{font-size:187.5%!important;}}想了解更多,可以参考这里:http://www.cnblogs.com/beidan/p/5275379.html#3382529。三、常见的一些效果的做法①页面板块可横向滑动一种就是我们经常见的,一些特卖活动、抢购活动的时候,需要出现横向滚动情况。效果图:不要以为这种效果会涉及到什么touch事件,要写多复杂的js。其实只用css就可以很简单地实现了。原理就是利用overflow属性。设置其水平方向滚动,垂直方向hidden即可。当然,还要配合一些其他的代码。具体css代码如下:ul.pinxiang-list{padding:10px;padding-top:0;padding-bottom:20px;width:100%;box-sizing:border-box;overflow-x:scroll;overflow-y:hidden;white-space:nowrap;float:left;}ul.pinxiang-listli{position:relative;display:inline-block;margin-right:5px;}这里最主要的就是要设置ul的宽度是100%,并且向左浮动。li要设置为display:inline-block.还有一个就是,如果你用谷歌调试的时候,会发现,效果是这样的:对,就是会出现一个明显的滚动条。但是如果你用真机,也就是用移动设备看的时候,你会发现其实滚动条是不会出现的。所以有时候做移动的东西,还是需要真机测试一下比较靠谱啊。另外要注意一个问题,由于li被display:inline-block.那么就有了inline的属性,默认。此元素会被显示为内联元素,元素前后没有换行符。并且,该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐。什么意思呢,简单来说就是这些li的对齐基线的默认方式是以最后一行的文字对齐的。看图:由图中可以明显看出,最后一个li由于没有图片撑起来,而它们的默认方式又是以最后一行文字为基准的,所以最后一个li就“掉”了下来。这个时候,我们就需要设置一下vertical-align这个属性的值了。设置为:vertical-align:middle。具体用法,可以看这里。这样设置了的话,就没有问题了哦。效果完成!!!
-
内存分配与回收策略
Java自动内存管理的两个问题:给对象分配内存回收分配给对象的内存对象的内存分配,往大方向讲,就是在堆上分配,对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能直接分配在老年代中,分配的规则不是百分之百固定的,其细节在于使用哪种垃圾收集器组合,还有虚拟机中与内存相关的参数。对象优先在Eden分配绝大多数情况,对象都在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机会发生一次MinorGC。虚拟机提供了-XX:+PrintGCDetails这个收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况。在实际应用中,内存回收日志一般是打印到文件后通过日志工具进行分析,不过本实验的日志并不多,直接阅读就能看的很清楚。测试内存分配代码:publicclassTestAllocation{privatestaticfinalint_1MB=1024*1024;/***VM参数:-XX:+UseSerialGC-verbose:gc-Xms20M-Xmx20M-Xmn10M-XX:+PrintGCDetails-XX:SurvivorRatio=8*/publicstaticvoidtestAllocation(){byte[]allocation1,allocation2,allocation3,allocation4;allocation1=newbyte[2*_1MB];allocation2=newbyte[2*_1MB];allocation3=newbyte[2*_1MB];allocation4=newbyte[4*_1MB];//出现一次MinorGC}publicstaticvoidmain(String[]args){TestAllocation.testAllocation();}}1234567891011121314151617运行结果:[GC(AllocationFailure)[DefNew:7129K->531K(9216K),0.0037131secs]7129K->6675K(19456K),0.0137564secs][Times:user=0.00sys=0.00,real=0.01secs]Heapdefnewgenerationtotal9216K,used4709K[0x00000000fec00000,0x00000000ff600000,0x00000000ff600000)edenspace8192K,51%used[0x00000000fec00000,0x00000000ff014930,0x00000000ff400000)fromspace1024K,51%used[0x00000000ff500000,0x00000000ff584c58,0x00000000ff600000)tospace1024K,0%used[0x00000000ff400000,0x00000000ff400000,0x00000000ff500000)tenuredgenerationtotal10240K,used6144K[0x00000000ff600000,0x0000000100000000,0x0000000100000000)thespace10240K,60%used[0x00000000ff600000,0x00000000ffc00030,0x00000000ffc00200,0x0000000100000000)Metaspaceused2573K,capacity4486K,committed4864K,reserved1056768Kclassspaceused285K,capacity386K,committed512K,reserved1048576K注意:使用64位的需要添加参数-XX:+UseSerialGC,使其强制使用SerialGC以上的方法试图分配3个2MB大小和一个4MB大小的对象,在运行通过-Xms20M-Xmx20M-Xmn10M三个参数限制了Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下的10MB分配给老年代。-XX:SurvivorRatio=0决定了新生代中Eden区与一个Survivor区的空间比例为8:1,从输出的结果也可以清晰地看到“edenspace8192K、fromspace1024K、tospace1024K”的信息,新生代的总可用空间为9216KB(Eden区+一个Survivor区的总容量)。执行testAllocation()中分配allocation4的语句时会发生一次MinorGC,这次GC的结果时新生代6651KB变为148KB,而总内存占用几乎没有减少(因为allocation1、allocation2、allocation3三个对象都是存活的,虚拟机几乎没有找到可回收的对象)。这次GC发生的原因是给allocation4分配内存的时候,发现Eden已经被占用了6MB。剩余空间已经不足以分配allocation4所需的4MB内存,因此发生MinorGC。GC期间虚拟机又发现已有的3个2MB大小的对象全部无法放入Survivor空间(仅有1MB),所以只好通过分配担保的机制提前转移到老年代去了。这次GC结束后,4MB的allocation4的对象顺利分配在Eden中,因此程序执行完的结果是Eden占用4MB(被allocation4占用),Survivor空闲,老年代被占用6MB(被allocation1allocation2allocation3占用)。通过GC日志可以证实这点。MinorGC和FullGC不同点:MinorGC:指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以MinorGC非常频繁,一般回收速度也比较快。。MajorGC/FullGC:指发生在老年代的GC,出现了MajorGC,经常会伴随至少一次的MinorGC(但非绝对的,在ParallelScavenge收集器的收集策略里就有直接进行MajorGC的策略选择过程)。MajorGC的速度一般会比MinorGC慢10倍以上。大对象直接进入老年代所谓大对象就是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串及数组(笔者例子中的byte[]数组就是典型的大对象)。大对象对虚拟机的内存分配来说就是一个坏消息(替Java虚拟机抱怨一句,比遇到一个大对象更加坏的消息就是遇到一群“朝生夕灭”的“短命大对象”,写程序的时候应当避免),经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来“安置”它们。虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代中分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝(复习一下:新生代采用复制算法收集内存)。代码:publicclassTestPretensureSizeThreshold{privatestaticfinalint_1MB=1024*1024;/***VM参数:-XX:+UseSerialGC-verbose:gc-Xms20M-Xmx20M-Xmn10M-XX:+PrintGCDetails-XX:SurvivorRatio=8*-XX:PretenureSizeThreshold=3145728*/publicstaticvoidtestPretenureSizeThreshold(){byte[]allocation;allocation=newbyte[4*_1MB];//直接分配在老年代中}publicstaticvoidmain(String[]args){TestPretensureSizeThreshold.testPretenureSizeThreshold();}}1234567891011121314151617运行结果:Heapdefnewgenerationtotal9216K,used1148K[0x00000000fec00000,0x00000000ff600000,0x00000000ff600000)edenspace8192K,14%used[0x00000000fec00000,0x00000000fed1f3f0,0x00000000ff400000)fromspace1024K,0%used[0x00000000ff400000,0x00000000ff400000,0x00000000ff500000)tospace1024K,0%used[0x00000000ff500000,0x00000000ff500000,0x00000000ff600000)tenuredgenerationtotal10240K,used4096K[0x00000000ff600000,0x0000000100000000,0x0000000100000000)thespace10240K,40%used[0x00000000ff600000,0x00000000ffa00010,0x00000000ffa00200,0x0000000100000000)Metaspaceused2572K,capacity4486K,committed4864K,reserved1056768Kclassspaceused285K,capacity386K,committed512K,reserved1048576K执行如上代码的testPretenureSizeThreshold()方法后,我们看到Eden空间几乎没有被使用,而老年代10MB的空间被使用了40%,也就是4MB的allocation对象直接就分配在老年代中,这是因为PretenureSizeThreshold被设置为3MB(就是3145728B,这个参数不能与-Xmx之类的参数一样直接写3MB),因此超过3MB的对象都会直接在老年代中进行分配。长期存活的对象进入老年代既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在老年代中。为了做到这点,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。读者可以试试分别以-XX:MaxTenuringThreshold=1和-XX:MaxTenuringThreshold=15两种设置来执行代码清单3-7中的testTenuringThreshold()方法,此方法中的allocation1对象需要256KB内存,Survivor空间可以容纳。当MaxTenuringThreshold=1时,allocation1对象在第二次GC发生时进入老年代,新生代已使用的内存GC后非常干净地变成0KB。而MaxTenuringThreshold=15时,第二次GC发生后,allocation1对象则还留在新生代Survivor空间,这时新生代仍然有1MB被占用。代码:publicclassTestTenuringThreshold{privatestaticfinalint_1MB=1024*1024;/***VM参数:-XX:+UseSerialGC-verbose:gc-Xms80M-Xmx80M-Xmn40M-XX:+PrintGCDetails-XX:SurvivorRatio=8-XX:MaxTenuringThreshold=1*-XX:+PrintTenuringDistribution*/@SuppressWarnings("unused")publicstaticvoidtestTenuringThreshold(){byte[]allocation1,allocation2,allocation3;allocation1=newbyte[_1MB];//什么时候进入老年代取决于XX:MaxTenuringThreshold设置allocation2=newbyte[16*_1MB];allocation3=newbyte[16*_1MB];allocation3=null;allocation3=newbyte[16*_1MB];}publicstaticvoidmain(String[]args){TestTenuringThreshold.testTenuringThreshold();}}1234567891011121314151617181920212223以MaxTenuringThreshold=1得到的结果:[GC(AllocationFailure)[DefNew:19374K->1555K(36864K),0.0073413secs]19374K->17939K(77824K),0.0073791secs][Times:user=0.00sys=0.00,real=0.01secs][GC(AllocationFailure)[DefNew:17939K->0K(36864K),0.0016595secs]34323K->17938K(77824K),0.0016844secs][Times:user=0.00sys=0.00,real=0.00secs]Heapdefnewgenerationtotal36864K,used16712K[0x00000000fb000000,0x00000000fd800000,0x00000000fd800000)edenspace32768K,51%used[0x00000000fb000000,0x00000000fc052040,0x00000000fd000000)**fromspace4096K,0%**used[0x00000000fd000000,0x00000000fd000000,0x00000000fd400000)tospace4096K,0%used[0x00000000fd400000,0x00000000fd400000,0x00000000fd800000)tenuredgenerationtotal40960K,used17938K[0x00000000fd800000,0x0000000100000000,0x0000000100000000)**thespace40960K,43%**used[0x00000000fd800000,0x00000000fe984970,0x00000000fe984a00,0x0000000100000000)Metaspaceused2573K,capacity4486K,committed4864K,reserved1056768Kclassspaceused285K,capacity386K,committed512K,reserved1048576K1234567891011以MaxTenuringThreshold=15得到的结果:[GC(AllocationFailure)[DefNewDesiredsurvivorsize2097152bytes,newthreshold15(max15)-age1:1592488bytes,1592488total:19374K->1555K(36864K),0.0089774secs]19374K->17939K(77824K),0.0090155secs][Times:user=0.00sys=0.00,real=0.01secs][GC(AllocationFailure)[DefNewDesiredsurvivorsize2097152bytes,newthreshold15(max15)-age2:1591648bytes,1591648total:17939K->1554K(36864K),0.0011282secs]34323K->17938K(77824K),0.0011471secs][Times:user=0.00sys=0.00,real=0.00secs]Heapdefnewgenerationtotal36864K,used18266K[0x00000000fb000000,0x00000000fd800000,0x00000000fd800000)edenspace32768K,51%used[0x00000000fb000000,0x00000000fc052040,0x00000000fd000000)fromspace4096K,37%used[0x00000000fd000000,0x00000000fd184960,0x00000000fd400000)tospace4096K,0%used[0x00000000fd400000,0x00000000fd400000,0x00000000fd800000)tenuredgenerationtotal40960K,used16384K[0x00000000fd800000,0x0000000100000000,0x0000000100000000)thespace40960K,40%used[0x00000000fd800000,0x00000000fe800010,0x00000000fe800200,0x0000000100000000)Metaspaceused2572K,capacity4486K,committed4864K,reserved1056768Kclassspaceused285K,capacity386K,committed512K,reserved1048576K1234567891011121314151617动态对象年龄判断对象的年龄到达了MaxTenuringThreshold可以进入老年代,同时,如果在survivor区中相同年龄所有对象大小的总和大于survivor区的一半,年龄大于等于该年龄的对象就可以直接进入老年代。无需等到MaxTenuringThreshold中要求的年龄。具体代码如下:publicclassAllocationTest2{privatestaticfinalint_1MB=1024*1024;/**-Xms20M-Xmx20M-Xmn10M-XX:SurvivorRatio=8-XX:+PrintGCDetails-XX:+UseSerialGC-XX:MaxTenuringThreshold=15-XX:+PrintTenuringDistribution**/publicstaticvoidtestTenuringThreshold2(){byte[]allocation1,allocation2,allocation3,allocation4;allocation1=newbyte[_1MB/4];allocation2=newbyte[_1MB/4];allocation3=newbyte[4*_1MB];allocation4=newbyte[4*_1MB];allocation4=null;allocation4=newbyte[4*_1MB];}publicstaticvoidmain(String[]args){testPretenureSizeThreshold2();}}1234567891011121314151617181920212223242526得到结果:[GC(AllocationFailure)[DefNewDesiredsurvivorsize524288bytes,newthreshold1(max15)-age1:1048576bytes,1048576total:5592K->1024K(9216K),0.0026321secs]5592K->5139K(19456K),0.0026687secs][Times:user=0.00sys=0.00,real=0.00secs][GC(AllocationFailure)[DefNewDesiredsurvivorsize524288bytes,newthreshold15(max15):5120K->0K(9216K),0.0009009secs]9235K->5139K(19456K),0.0009171secs][Times:user=0.00sys=0.00,real=0.00secs]Heapdefnewgenerationtotal9216K,used4178K[0x00000000fec00000,0x00000000ff600000,0x00000000ff600000)edenspace8192K,51%used[0x00000000fec00000,0x00000000ff014930,0x00000000ff400000)fromspace1024K,0%used[0x00000000ff400000,0x00000000ff400000,0x00000000ff500000)tospace1024K,0%used[0x00000000ff500000,0x00000000ff500000,0x00000000ff600000)tenuredgenerationtotal10240K,used5139K[0x00000000ff600000,0x0000000100000000,0x0000000100000000)thespace10240K,50%used[0x00000000ff600000,0x00000000ffb04c20,0x00000000ffb04e00,0x0000000100000000)Metaspaceused2573K,capacity4486K,committed4864K,reserved1056768KclassspaceusedboolTenuredGeneration::promotion_attempt_is_safe(size_tmax_promotion_in_bytes)const{//老年代最大可用的连续空间size_tavailable=max_contiguous_available();//每次晋升到老年代的平均大小size_tav_promo=(size_t)gc_stats()->avg_promoted()->padded_average();//老年代可用空间是否大于平均晋升大小,或者老年代可用空间是否大于当此GC时新生代所有对象容量boolres=(available>=av_promo)||(available>=max_promotion_in_bytes);returnres;}
-
C#开发基础跨平台物联网通讯框架 ServerSuperIO
ServerSuperIO详细介绍ServerSuperIO简称SSIO,是一个C#跨平台物联网通讯框架。C#开发基础跨平台物联网通讯框架ServerSuperIO一.SSIO的特点轻型高性能通信框架,适用于多种应用场,轮询模式、自控模式、并发模式和单例模式。设备驱动、IO通道、控制模式场景协调统一。设备驱动内轩命令驱动器、命令缓存器、自定义参数和实时数据元素。框架平台支持按设备命令优先级别进行调度,保证高级别命令及时发送。一个设备驱动同时支持串口和网络两种通讯方式,可以监视IO通道数据。一个设备驱动,在网络通讯时可以支持TCPServer和TCPClient两种工作模式。内置显示视图接口,满足不同显示需求。内置服务组件接口,可以自定义完成OPC服务、4-20mA输出、LED大屏显示、短信服务、以及多功能网关服务。可以创建多服务实例,完成不同业务的拆分。支持跨平台部署,可以运行在Linux和Windows系统。二.SSIO概述SSIO通信框架的设计思想是在SuperIO(SIO)基础上发展而来,并没有高大上的技术,主要是工作经验的积累,适合于不同应用场景的物联网的数据采集与交互。SSIO和SIO并不是简单的对IO高性能的操作,而是设备驱动、IO通道、控制模式和实际硬件设备之间的协调机制,各方面之间无缝衔接和运行,也是为了解决现实工作和应用场景的一些痛点。软硬件之间的数据交互,并且面临着复杂的现场环境:(1)复杂的、多样的通讯协议。有标准的协议,例如:Modbus等,也有很多根据标准协议修改的协议格式、以及自定义协议格式,并且千差万别。对于不好的软件架构,疲于应对,增加设备或协议要对整个软件进行梳理,往往在此过程中出现新的问题或BUG。(2)针对不同用户对软件界面或功能的要求有很大不同,使之满足不同用户的显示要求,可以自定义数据显示界面。那么就需要提供显示视图接口,与设备驱动进行交互。(3)既然现场设备的数据被采集上来,那么就需要对其进行处理,不仅仅是保存、查询、报表等,还有:数据转发、数据输出(OPC、模拟量、大屏等)等。那么就需要提供服务性的接口,与设备驱动进行交互。(4)通讯链路的多种性,对于同一个设备可能要支持RS232/RS485/RS422、RJ45、3G/4G等通讯方式,所以对于一个设备要对应多种通讯方式(串口和网络),也给我们的开发造成很大的障碍。(5)设备驱动、IO通道和实际的现场硬件终端之间链路复杂,有可能:一个设备驱动对应一个IO通道、一个设备驱动对应多个IO通道、多个设备驱动对应一个IO通道等情况。(6)既然设备与服务端进行数据交互,那么就应该对设备的通讯状态、IO状态、以及设备本身的状态进行监控,这样设备才处于可维护状态。(7)软件各版本、以及软件与硬件之间的兼容性很差,管理起来错综复杂。在框架平台稳定的情况下,只需要更新设备驱动。为了解决以上诸多问题,开发一个软件框架,支持二次开发。在不对软件框架改动的情况下,能够很方便的接入设备、维护设备、集成设备、处理设备业务数据等。软件框架相对稳定,把容易变化的部分进行灵活设计。三.控制模式(1)轮询模式:当串口和网络通讯时都可以使用这种控制模式。当有多个设备连接到通讯平台时,通讯平台会轮询调度设备进行通讯任务。某一时刻只能有一个设备发送请求命令、等待接收返回数据,这个设备完成发送、接收(如果遇到超时情况,则自动返回)后,下一个设备才进行通讯任务,依次轮询设备。如下图:(2)并发模式:只有网络通讯时可以使用这种控制模式。并发通讯模式是集中发送所有设备的请求指令,框架是采用循环同步方式发送请求命令。还有进一步提高的机会,采用并行异步方式集中发送请求命令。硬件设备接收到指令后进行校验,校验成功后返回对应指令的数据,通讯平台异步监听到数据信息后,进行接收操作,然后再进行数据的分发、处理等。如下图:(3)自控模式:只有网络通讯时可以使用这种控制模式。自控通讯模式与并发通讯模式类似,区别在于发送指令操作交给设备驱动本身进行控制,或者说交给二次开发者,二次开发者可以通过时钟定时用事件驱动的方式发送指令数据。硬件设备接收到指令后进行校验,校验成功后返回对应指令的数据,通讯平台异步监听到数据信息后,进行接收操作,然后再进行数据的分发、处理等。自控通讯模式可以为二次开发者提供精确的定时请求实时数据机制,使通讯机制更灵活、自主,如果多个设备驱动使用同一个IO通道的话,时间控制会有偏差。如下图:(4)单例模式:只有网络通讯时可以使用这种控制模式。在一个服务实例内只能有一个设备驱动,相当于一个设备驱动对应着N多个硬件设备终端。更适合通讯的数据协议有固定的标准,以命令关键字处理不同的数据。适用于高并发的硬件终端设备主动上传数据,服务器端根据数据信息进行处理和返回相应的数据。如下图:四.跨平台Windows和Linux(1)Windows运行效果(2)Linux运行效果