精华内容
下载资源
问答
  • 软件危机定义: 是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。 表现在: (1)对于软件开发的成本和进度的估计很不准确。 (2)开发的软件产品不能完全满足用户要求,用户对已完成的软件系统不满意...

    软件危机定义:
    是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。
    表现在:
    (1)对于软件开发的成本和进度的估计很不准确。
    (2)开发的软件产品不能完全满足用户要求,用户对已完成的软件系统不满意的现象常常发生。
    (3)开发的软件可靠性差。
    (4)软件通常没有适当的文档。
    (5)软件的可维护性差。
    (6)软件开发生产率提高的速度,远远跟不上计算机应用普及深入的趋势。
    原因:
    (1)软件的规模愈发庞大;
    (2)软件开发的管理困难。
    (3)成功的软件开发经验没被很好地应用。
    (4)软件开发和维护中千金错误认识和方法的形成可以归结与计算机发展早期软件开发的个体化特点。
    (5)软件开发技术落后。
    (6)生产方式落后。
    (7)开发工具落后,生产率提高缓慢。
    如何避免:
    从软件开发的工程化方法入手,即用现代工程的概念原理、技术和方法去指导软件的开发、管理和维护,这就是软件工程思想和方法。具体措施:
    (1)使用好的软件开发技术和方法;
    (2)要有良好的组织、严密的管理,各类人员协同配合,共同完成任务;
    (3)使用好的软件开发工具,提高软件生产率;
    (4)建立严格的文档资料,重视软件开发过程的阶段评审。

    展开全文
  • 【运行异常】常见OOM现象

    千次阅读 2018-08-08 21:14:10
    常见OOM现象 《java 特种兵 上册》 3.6 常见的OOM现象( 136-146页),看此节后的总结。 OOM的实际场景是很多的,这里介绍常见的,同时结合网络与实际测试中的一些资料信息。 一.HeapSize OOM(堆空间内存溢出) ...

    常见OOM现象

    《java 特种兵 上册》 3.6 常见的OOM现象( 136-146页),看此节后的总结。

    OOM的实际场景是很多的,这里介绍常见的,同时结合网络与实际测试中的一些资料信息。

    一.HeapSize OOM(堆空间内存溢出)

    关键字:java.lang.OutOfMemoryError:java heap space

    意思:堆空间溢出。老年代区域剩余的内存,已经无法满足将要晋升到老年代区域的对象大小,会报此错。

     一般来说,绝大部分都是这种情况。大量空间占据了堆空间,而这些对象持有强引用,导致无法回收,当对象大小之和大于由xmx参数指定的堆空间大小时,溢出错误就发生了。

    发生堆内存不足的原因可能有:

    1)设置的堆内存太小,而系统运行需要的内存要超过这个设置值

    2)内存泄露。关注系统稳定运行期,full gc每次gc后的可用内存值是否一直在增大。

    3)由于设计原因导致系统需要过多的内存,如系统中过多地缓存了数据库中的数据,这属于设计问题,需要通过设计减少内存的使用。

    4)分析线程执行模型和它们持有的JVM里的短生命对象

    代码层面处理方式和手段:

    1)看代码是否有问题;.eg:List.add(" ")在一个死循环中不断的调用add却没有remove。---间接内存泄露

    2)代码没有问题,并发导致。

    并发导致内存还不能被gc掉,或很多对象还会引用,那就说明对象所在的生命周期范围内的代码部分还没执行结束。

    解决方法有:

    1.代码提速。这样可以使得相同对象的生存时间更短。更快被GC。

    2.对于长生命周期对象(如I/O操作)对象后续不用了,objecft=null可以辅助GC,一旦方法脱离了作用域,相应的局部变量应用就会被注销。

    3.代码无法优化后,程序跑的飞快,还是出现OOM,考虑到去修改参数配置

     eg:堆空间的大小,堆空间要设置的足够大(相对),如果太大,发生FULL GC会很恐怖

    4.内存泄露:内存可能在某些情况增加几十字节空间但未能释放,每次被GC,很老的对象被GC的较慢。

    eg1:Session中放数据,Session回话消失才会被注销,但是会话要很长的时间才会被注销。

    eg2.不断full gc,每次时间变长频率变小。当次数达到一定量时,平均full gc时间达到一定比例时会报:OutOfMemoryError:GC over head limit exceeded

    不断的FULLGC就是不抛出OOM的现象,出现这种现象通常是一些藏匿的Bug或配置导致。

    eg3:Tomcat的session导致,session信息保存在全局的currentHashMap中,大量的HTTPClient访问创建的临时session。但并没有保存系统中为之分配的SessionKey中和相关的Cookies信息,导致每次请求都创建session(几十个字节,request.getSession被调用时),一般看不出来,是一个堆积如山的过程。

    多种OOM,大多是指系统一个静态引用指向了一个只增不减的对象(例如 hashMap)

    GC效率低下引起的OOM

    如果堆空间小,那GC所占时间就多,回收所释放的内存不会少。根据GC占用的系统时间,以及释放内存的大小,虚机会评估GC的效率,一旦虚机认为GC的效率过低,就有可能直接抛出OOM异常。但这个判定不会太随意。

    Sun 官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收 了不到2%的堆内存。用来避免内存过小造成应用不能正常工作。“

    一般虚机会检查几项:

      ● 花在GC上的时间是否超过了98%

      ● 老年代释放的内存是否小于2%

      ● eden区释放的内存是否小于2%

      ● 是否连续最近5次GC都出现了上述几种情况(注意是同时出现)

    只有满足所有条件,虚机才会抛出OOM:GC overhead limit exceeded

    这个只是辅助作用,帮助提示系统分配的堆可能大小,并不强制开启。有关闭开关-XX:-UseGCOverheadLimit来禁止这种。

    此参数的意义:当频繁Full GC导致程序僵死现象,一致耗着,如果加上-XX:+UseGCOverheadLimit参数就可以让程序提前退出,避免僵死程序长期占用资源。

    遇到此种情况如何解决?

    解决这种问题两种方法:

    1)增加参数,- XX:-UseGCOverheadLimit,关闭这个特性,同时增加heap大小,-Xmx1024m。

    2)排查并优化消耗内存资源代码。

    如果生产环境中遇到了这个问题,在不知道原因时可以通过-verbose:gc -XX:+PrintGCDetails看下到底什么原因造成了异常。通常原因都是因为old区占用过多导致频繁Full GC,最终导致GC overhead limit exceed。如果gc log不够可以借助于JProfile等工具查看内存的占用,old区是否有内存泄露。分析内存泄露还有一个方法-XX:+HeapDumpOnOutOfMemoryError,这样OOM时会自动做Heap Dump,可以拿MAT来排查了。还要留意young区,如果有过多短暂对象分配,可能也会抛这个异常。

    日志的信息不难理解,就是每次gc时打条日志,记录GC的类型,前后大小和时间。举个例子。

    33.125: [GC [DefNew: 16000K->16000K(16192K), 0.0000574 secs][Tenured: 2973K->2704K(16384K), 0.1012650 secs] 18973K->2704K(32576K), 0.1015066 secs]

    100.667:[Full GC [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm : 2999K->2999K(21248K)], 0.0150007 secs] 

    GC和Full GC代表gc的停顿类型,Full GC代表stop-the-world。箭头两边是gc前后的区空间大小,分别是young区、tenured区和perm区,括号里是该区的总大小。冒号前面是gc发生的时间,单位是秒,从jvm启动开始计算。DefNew代表Serial收集器,为Default New Generation的缩写,类似的还有PSYoungGen,代表Parallel Scavenge收集器。这样可以通过分析日志找到导致GC overhead limit exceeded的原因,通过调节相应的参数解决问题。

    案例一原文

    现象:某应用系统负载升高,响应变慢,发现应用进行频繁GC,甚至出现OutOfMemroyError: GC overhead limt exceed的错误日志。 

    原因:因为这个项目是个历史项目,使用了Hibernate ORM框架,在Hibernate中开启了二级缓存,使用了Ehcache;但是在Ehcache中没有控制缓存对象的个数,缓存对象增多,导致内存紧张,所以进行了频繁的GC操作。 

    总结:使用本地缓存(如Ehcache、OSCache、应用内存)时,一定要严格控制缓存对象的个数及声明周期。

    案例二原文

    现象:某应用系统改变用户web接口(使用JSON作为数据负载)后,性能下降,出现了“OutOfMemoryError: Java heap space”问题并伴有过多的垃圾收集。通过verbose:gc 日志分析确认32-bit HotSpot JVM 老年代空间(1 GB 容量)被完全消耗。

    分析过程:

    1)线程转储数据分析,这种数据通常会告诉在JVM堆里面内存分配的罪魁祸首线程。同样的它也会显示任何一个尝试从远程系统发送和接受数据的贪婪或者阻塞的线程。观察到的OOM事件和阻塞线程之间有很近的关联关系。线程出现了阻塞并且花费了很长时间从远程系统里读和接收JSON响应。

    2)堆转储分析,找出堵塞线程和JVM堆转储分析之间的关联,并且确定这个阻塞线程从堆里占用了多少内存。

    --》MAT工具打开文件

    -》直方图查看前通过过ExecuteThread(用于对象的创建和执行)过滤。总共有多少个线程被创建,这些线程总共持有的内存占用是多少。--判断问题核心是不是源于线程自己的内存占有。

    --》深入分析线程内存持有。右键点击ExecuteThread 类并且选择“列出所有外部引用的对象”。--发现“STUCK(阻塞)”线程和大量内存占用有很大关系。

    ---》线程局部变量鉴别。展开几个线程示例并了解内存占用的原始来源。---发现根源在于大量的JSON数据响应。

    总结:发现少量的线程花费太多时间去读取和接收JSON响应,这是大量数据负载的一个明显的症状。通过方法局部变量创建的短生命对象也会出现在堆转储分析中。然而,其中的一些仅仅能被他们的父线程看到,这是由于他们没有被其他对象引用,比如这个例子。为了找出真正的调用者你或许也需要分析这个线程栈,随后通过代码审查确定最终的根源。在某些情形下,大量的JSON数据可以达到45M以上。使用了32位JVM而且仅仅只有1G的老年代,结果只需要几个线程就足够触发一些性能下降。

     

    案例三:jsp页面导致tomcat内存溢出

    背景:测试kafka队列时,消费者使用一个jsp页面模拟,使用tomcat中间件。

    现象:测试一段时间后,发现JVM内存持续增加,涨到一定值后就一直频繁做gc且JVM内存并没有释放多少,同时频繁gc引起CPU使用率变高。dump堆内存,分析查看主要是session占用。

    分析:发现每请求一次jsp页面,会产生一个session对象,并且这个对象30分钟(web.xml里设置的)后才过期。

    解决方法:

    1.在page指令里添加session=“false”。设置jsp页面session参数  <%@ page session="false" language="java" pageEncoding="UTF-8" %>

    2.在web.xml里把session的过期时间设成0。

    参考:JSP页面导致tomcat内存溢出一例session不及时释放导致内存溢出的性能问题分析

    二.PermGen OOM(永久代内存溢出)

    关键字:java.lang.OutOfMemoryError:PermGen space

    永久代(PermGen space)是JVM实现方法区的地方,因此该异常主要设计到方法区和方法区中的常量池。永久代存放的东西有class和一些常量。perm是放永久区的。如果一个系统定义了太多的类型,那永久区可能会溢出。jdk1.8中,被称为元数据区。

    A.常量池(JDK1.6,JDK1.7以后常量池不会放在永久代中了。)

    string常量对象会在常量池(包含类名,方法名,属性名等信息)中以hash方式存储和访问,hash表默认的大小为1009,当string过多时,可以通过修改-xx:stringtableSize参数来增加Hash元素的个数,减少Hash冲突。

    当常量池需要的空间大于常量池的实际空间时,也会抛出OutOfMemoryError: PermGen space异常。

    例如,Java中字符串常量是放在常量池中的,String.intern()这个方法运行的时候,会检查常量池中是否存和本字符串相等的对象,如果存在直接返回对常量池中对象的引用,不存在的话,先把此字符串加入常量池,然后再返回字符串的引用。那么可以通过String.intern方法来模拟一下运行时常量区的溢出.

    B.class加载

    由于class被卸载的条件十分的苛刻,这个class所对应的classLoader下面所有的class都没有活对象的应用才会被卸载。

    方法区(Method Area)不仅包含常量池,而且还保存了所有已加载类的元信息。当加载的类过多,方法区放不下所有已加载的元信息时,就会抛出OutOfMemoryError: PermGen space异常。主要有以下场景: 

    • 使用一些应用服务器的热部署的时候,会遇到热部署几次以后发现内存溢出了,这种情况就是因为每次热部署的后,原来的class没有被卸载掉。

    • 如果应用程序本身比较大,涉及的类库比较多,但分给永久代的内存(-XX:PermSize和-XX:MaxPermSize来设置)比较小的时候也可能出现此种问题。

    解决方法:在每次CGlib动态创建时,都重新给它设置一个classLoader,这样在运行代码就不会出现OOM,会发现大量的class被卸载。

    VisualVm工具,查看PermGen标签页、类加载标签页中的趋势。随着类装载的数量增加,最终会出现了java.lang.OutOfMemoryError: PermGen space。

     

    示例:如果不断产生新类,而没有回收,那最终很可能会导致永久区溢出。
    解决的话从几方面入手:
    ● 增加MaxPermSize
    ● 减少系统需要的类数量
    ● 使用classloader合理的装载各个类,并定期进行回收

    加+PrintGCDetails参数,打印日志可看地gc情况。+TraceClassUnloading,查看日志。  

    什么是Java的永久代(PermGen)内存泄漏 

    在反射的过程中,会有一些新的类被动态创建出来,如果系统中频繁地有新的类被动态创建出来,并且将禁止了class的GC,此时很容易导致永久内存区溢出。

    增加-verbose:class很容易观察到class输出。

    最好不要加-noclassgc选项(运行期间就不会做class的GC),加上这个选项后,势必需要更大的永久内存,很容易造成永久内存区溢出。

    java.lang.OutOfMemoryError: Metaspace

    JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap,譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。但永久代仍存在于JDK1.7中,并没完全移除。 
    JDK 8.HotSpot JVM使用本地化的内存存放类的元数据,这个空间叫做元空间(Metaspace)。官方定义:”In JDK 8, classes metadata is now stored in the native heap and this space is called Metaspace”。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:-XX:MetaspaceSize、-XX:MaxMetaspaceSize。 

    VisualVm工具,查看Metaspace标签页、类加载标签页中的趋势,可以看到使用的空间大小随类装入的数量增加而增加,这也说明了Metaspace是用来存放类的元数据的。 

    三.DirectBuffer OOM(直接内存内存溢出)

    关键字:OutOfMemoryError: Direct buffer memory 

    Java中普通I/O用输入/输出流方式实现,输入流InputStream(终端—>直接内存->JVM),输出流(JVM->直接内存->终端),这一过程中有kenel与JVM之间的拷贝(很多次),为了使用直接内存,Java是有一块区域叫DirectBuffer,不是JavaHeap而是cHeap的一部分。

    NIO支持直接内存的使用,也就是通过java代码,获得一块堆外的内存空间,这块空间是直接向操作系统申请的。它的申请速度比堆内存慢,但访问速度快。
    对于那些可复用的,并会被经常访问的空间,使用直接内存可提高系统性能。但由于直接内存没有被java虚机完全托管,若使用不当,也容易触发溢出,导致宕机。

    ByteBuffer有两种一种是heap ByteBuffer,该类对象分配在JVM的堆内存里面,直接由Java虚拟机负责垃圾回收,一种是direct ByteBuffer是通过jni在虚拟机外内存中分配的。通过jmap无法查看该快内存的使用情况。只能通过top来看它的内存使用情况。JVM堆内存大小可以通过-Xmx来设置,同样的direct ByteBuffer可以通过-XX:MaxDirectMemorySize来设置,此参数的含义是当Direct ByteBuffer分配的堆外内存到达指定大小后,即触发Full GC。注意该值是有上限的,默认是64M,最大为sun.misc.VM.maxDirectMemory(),在程序中中可以获得-XX:MaxDirectMemorySize的设置的值。

    direct ByteBuffer通过full gc来回收内存的,direct ByteBuffer会自己检测情况而调用system.gc(),但是如果参数中使用了DisableExplicitGC那么就无法回收该快内存了,-XX:+DisableExplicitGC标志自动将System.gc()调用转换成一个空操作,就是应用中调用System.gc()会变成一个空操作。那么如果设置了就需要手动来回收内存。那么除了FULL GC还有别的能回收direct ByteBuffer吗?CMS GC会回收Direct ByteBuffer的内存。

    直接内存不一定触发full gc(除非直接内存使用量达到了-XX:MaxDirectMemorySize的设置),保证它不溢出的方法是合理进行full gc(full gc时会对这里做gc)的执行,或设定一个系统实际可达的-XX:MaxDirectMemorySize值(默认是-xmx的设置)。

    如果系统的堆内存少有GC发生,而直接内存申请频繁,会比较容易导致直接内存溢出。(32位机器比较明显)
    为避免直接内存溢出,

    1)合理执行显示GC,可降低概率;

    2)设置合理的-XX:MaxDirectMemorySize值,避免发生;

    3)设置一个较小的堆在32 虚机上可是到更多的内存用于直接内存。

    手动释放本地内存?DirectByteBuffer持有一个Cleaner对象,该对象有一个clean()方法可用于释放本地内存,需要的时候可以调用这个方法手动释放本地内存。

     

    如果应用里有任何地方用了direct memory,那么使用-XX:+DisableExplicitGC要小心。如果用了该参数而且遇到direct memory的OOM,可以尝试去掉该参数看是否能避开这种OOM。如果担心System.gc()调用造成full GC频繁,可以尝试 -XX:+ExplicitGCInvokesConcurrent 参数 ([HotSpot VM] JVM调优的"标准参数"的各种陷阱)。

     

    eg:设置-xx:MaxDirectMemorysize:256    分配一个ByteBufferallocateDirect(257*1024*1024)就会导致OOM。

     

    本地内存泄露?

    分析gc信息,不存在Java堆内存的泄漏,但分析java进程,发现Java进程的总内存越来越大,并且无停止上涨的迹象,直到整个系统崩溃。它的定位比较复杂。

    可能原因有:

    1)如果系统存在JNI调用,本地内存泄露可能存在于JVM代码中。结合pmap等命令初步确认。

    2)JDK的bug。如果第一步没问题,通过更新jdk版本,排除下。

    3)操作系统bug 

    本地内存泄漏可能还会引发异常:java.lang.OutOfMemoryError: unable to create new native thread

    四.StackOverflowError(栈内存溢出错误)

    关键字:StackOverflowError

    栈(JVM Stack)存放主要是栈帧( 局部变量表, 操作数栈 , 动态链接 , 方法出口信息 )的地方。注意区分栈和栈帧:栈里包含栈帧。

    与线程栈相关的内存异常有两个:

    • StackOverflowError(方法调用层次太深,内存不够新建栈帧)

    • OutOfMemoryError(线程太多,内存不够新建线程)

    1.通常都是程序的问题,JVM对栈帧的大小设置已经很大了。

    2.程序运行过程中,方法分派时,会分配frame来存放本地变量,栈,pc寄存器等信息,方法再调用方法会导致Java栈空间无止境的增长(死递归),Java的解决方法是:设置一个私有栈(不在堆内存,而是在NativeMemory),这个栈的空间大小,通过-Xss来设置,数量级在256K-1MB。如果使用空间超过了-Xss限制,请求新建栈帧时,栈所剩空间小于栈帧所需空间,就会出现StackOverflowError。

    3.eg:死递归

    死递归和死循环的区别:死循环类似于while(true)的操作,它的线程栈空间使用不会递增。而死递归需要记录退回的路径,递归过程中调用方法,每个方法运行过程中的本地变量。也就是要记录上下文信息。这些信息会随着内容的增加,占用很大的内存空间。

    死递归:

    eg:1.组件的复用。

         2.子类调用父类(复用父类的方法),父类调用子类(达到多态的效果),这中间要经过许多方法,可能形成环,进而形成死递归。

         3.三方框架的问题。

    这种一般都是程序有问题。分析它时,输出的线程栈信息明确地说明了调用路径。

    五.其他内存溢出

    A.过多线程导致OOM:unable to creat new native thread

    因为虚拟机会提供一些参数来保证堆以及方法区的分配,剩下的内存基本都由栈来占有,而且每个线程都有自己独立的栈空间(堆,方法区为线程共有)。所以:

    • 如果把虚拟机参数Xss调大了,每个线程的占用的栈空间也就变大了,那么可以建立的线程数量必然减少

    • 公式:线程栈总可用内存=JVM总内存-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存

    如果-Xmx或者-XX:MaxPermSize太大,那么留给线程栈可用的空间就越小,在-Xss参数配置的栈容量不变的情况下,可以创建的线程数也就越小。

    如果JVM正在请求操作系统创建一个本地线程,而操作系统无法创建的时候,就会出现这个报错信息。JVM中可以生成的最大线程数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大可创建的线程数量(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响。Linux下JVM中可生成的最大Thread数量

    简单理解为一个jvm进程的最大线程数为:虚拟内存/(堆栈大小*1024*1024),也就是说虚拟内存越大或堆栈越小,能创建的线程越多。

     

    原因:物理内存不够用或者OS限制了单个进程使用的最大内存,大量的线程分配时,就有可能导致占用的Native Memory(线程私有栈)很多。 

    每个线程开启都会占用系统内存,线程量太大时,也会导致OOm 。线程的栈空间也是在堆外分配的,和直接内存类似。如果想让系统支持更多的线程,那应使用一个较小的堆空间。

    示例1,想要创建 1500个线程,但1200多失败了。提示“unable to create new native thread",表示系统创建线程数量已经饱和,其原因是java进程已经达到了可使用的内存上限。

    示例2,死循环中创建线程并启动,线程内部申请变量,本身不退出。而且设置Os对进程内存的限制。

     

    分析思路:

    1)系统当前有过多的线程,操作系统无法再创建更多的线程。可以通过打印线程堆栈,先查看总的线程数量。可能原因:是否系统创建的线程被阻塞或者死锁,导致系统中的线程越来越多,直到超过最大限制。或者操作系统自身能创建的线程数量太少。

    2)swap分区不足。

    3)堆内存设置过大。

    4)系统对进程内存限制,用户最大打开的进程数限制

    max user processes用户最大打开的进程数这个值默认是1024,看官方说明,指用户最多可创建线程数,因为一个进程最少有一个线程,所以间接影响到最大进程数。

     

    解决从以下几方面下手:

    1)减少堆空间  -xmx,可预留更多内存用于线程创建,因此程序可正常执行。

    2)减少每一个线程所占用的内存空间,-xss参数指定线程的栈空间     -xmx1g -xss128K    栈空间小了,栈溢出风险会提高。

    3)打开/etc/security/limits.d/90-nproc.conf,把对应用户soft    nproc     1024这行的1024改大就行了。

    总体思路:合理减少线程总数,减少最大堆空间,减少线程的栈空间也可行。 系统限制。

    B.request{} byte for {}out of swap

    地址空间不够用(不一定是物理地址,还有swap,显卡,网卡)

    这个错误是当虚拟机向本地操作系统申请内存失败时抛出的。这和用完了堆或者持久化中的内存的情况有些不同。这个错误通常是在程序已经逼近平台限制的时候产生的。这个信息是可能已经用光了物理内存以及虚拟内存了。由于虚拟内存通常是用磁盘作为交换分区,因此最先想到的解决方法可能是先增加交换分区的大小,但这个方法可能不太好用。

    C.IoException:too many open files

    这个与OOM无关,但也是系统级别问题。它发生这类问题代表系统的某些设计存在问题或某些使用已经达到了权限。

    错误提示:打开太多的文件,也可能是本地的socket打开太多,而没有被关闭,也就是说有太多没有关闭套接字的导致。

     

    遇到OOM时,先大致分析原因,加上内存溢出后dump内存参数,设定参数后,出OOM会dump文件。用MAT或其他工作来分析 。

    D、java.lang.OutOfMemoryError: Requested array size exceeds VM limit

     当准备创建一个超过虚拟机允许的大小的数组时,这条错误就会出现在眼前。64位的操作系统上,JDK7,如果数组的长度是Integer.MAX_VALUE-1,就会出现。

    其他可参考资料:

    写代码实现堆溢出、栈溢出、永久代溢出、直接内存溢出

    参考:https://www.cnblogs.com/kongzhongqijing/articles/7283599.html

    展开全文
  • 如果说数据不在ACID特性的保护下会发生不一致的现象,那么:  在ACID的保护下,是不是数据就一定不会产生不一致的现象呢?  在关系数据库系统中,多个会话(session)可以访问同一个数据库的同一个表的同一行...


        如果说数据不在ACID特性的保护下会发生不一致的现象,那么:

        ACID的保护下,是不是数据就一定不会产生不一致的现象呢

        在关系数据库系统中,多个会话(session)可以访问同一个数据库的同一个表的同一行数据。这样,对于数据而言,就意味着在同一个时间段内,有多个会话可以对其施加操作(或读操作或写操作),读写操作施加的顺序不同以及事务中A特性对事务结果的影响(或成功或失败,即要么提交要么回滚),这三种因素叠加在一起,会存在几种对数据有不同影响的情况:

    读读操作:如果同时只存在多个读操作,对于数据自身则没有影响;既读和读操作互不相应数据的一致性,读读操作可以并发执行。

    读写操作:如果读写操作都存在,因写在前读在后(如脏读现象)、读在前写在后(如不可重复读现象)、或者读在前写在后然后又读(如幻象现象),就可能因数据被写而导致另外一个读操作的会话读到错误的数据

    写写操作:如果同时存在多个写操作,写写操作直接改变了数据在同一时刻的语义,这就更不被允许,所以写写操作通常不允许被并发执行。但是,如果不做并发控制,写写并发操作也会带来数据异常现象。

    这三种情况的第二种,对应了SQL标准中定义的三种数据异常的现象,注意这三种异常都是针对某个事务(第2.2.1节称这样的事务为“主事务”)的读操作而言的。SQL2003标准对于数据异常现象的定义如下:

    The isolation level specifies the kind of phenomena that can occur during the execution of concurrent SQL-transactions. The following phenomena are possible:

    1) P1 (“Dirty read”): SQL-transaction T1 modifies a row. SQL-transaction T2 then reads that row before T1 performs a COMMIT. If T1 then performs a ROLLBACK, T2 will have read a row that was never committed and that may thus be considered to have never existed.

    2) P2 (“Non-repeatable read”): SQL-transaction T1 reads a row. SQL-transaction T2 then modifies or deletes that row and performs a COMMIT. If T1 then attempts to reread the row, it may receive the modified value or discover that the row has been deleted.

    3) P3 (“Phantom”): SQL-transaction T1 reads the set of rows N that satisfy some <search condition>. SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the <search con-dition> used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same

    <search condition>, it obtains a different collection of rows.

    怎么理解上面的内容呢?从SQL标准的定义可以看出:

    首先,涉及到了并发事务(concurrent SQL-tra nsactions):至少有两个事务同时发生,如上面所举的三种异常现象中,分别使用了事务T1T2。但是,更为复杂的情况,如下一节所谈到的“写偏序(write skew)”现象的发生可以是两个或三个事务同时发生。

    其次,涉及到了隔离级别(isolation level):如果多个事务是“可串行化”的,则意味着事务之间不应该互相影响(不是“一定互不影响”而是“不应该互相影响”),即逻辑上不应当存在“读写”冲突,所以数据库引擎实现时应该避免“读写”冲突造成的数据不一致的现象。避免的含义就是在数据库引擎编码实现的时候,采取并发控制技术,消除“脏读”、“不可重复读”、“幻象”这三种现象,采取的技术就是分级控制(不同的隔离级别),分别使用“读已提交(READ COMMITTED)”、“可重复读(REPEATABLE READ)”和“串行化(SERIALIZABLE)”这几种隔离级别,来应对这三种数据不一致的现象。

    数据操作的对象,脏读和不可重复读是以“row”(一行)为单位,而幻象现象操作的是一个数据集(零行到多行)。

        下面,我们把SQL标准的话语转为一个表格,如表1-2,来更好地理解一下三种异常现象。

    1-2 SQL标准定义的三种读数据异常现象

     

    脏读

    不可重复读

    幻象

     

    P1 (Dirty read)

    P2 (Non-repeatable read)

    P3 (Phantom)

    时间

    T1

    T2

    T1

    T2

    T1

    T2

    t0

    W(row)-Update

     

    R(row)

     

    R(rows)-WHERE<conditon>

     

    t1

     

    R(row)

     

    W(row)-Update/Delete

     

    W(rows)- Insert-<conditon>

    t2

    Rollback

     

     

    Commit

    R(rows)-WHERE<conditon>

     

    t3

     

     

    R(row)

     

     

     

    说明:

    表格头两行,表明SQL标准定义的三种异常现象,分别是脏读、不可重复读、幻象。

    表格第一列,时间值列,表明时间值在逐渐增长,即t0<t1<t2<t3

    对于每一种异常现象,都分为2个列,分别是两个并发的事务,各自命名为T1事务和T2事务。

    表格中的R(row),表示读row数据对象;W(row)表示写row对象,读写操作的是同一个数据对象rowW(row)-Update/Delete后面的Update/Delete表示的写操作是DML语句中的UPDATEDELETE语句产生的写数据库对象row的操作。

    带有“R(rows)-WHERE<conditon>”的表示SQL语句读数据(通常是SELECT语句)带有WHERE子句,此子句的条件表达式是“<conditon>

    带有“W(rows)-Update/Insert-<conditon>”的表示写操作生成的数据满足与其他事务读操作带有的相同的条件表达式“<conditon>”,且此写操作要么是UPDATE,要么是INSERT语句。

    带有背景颜色的,表示其对应时刻,如果发生对应的操作,将引发异常现象。

    对于脏读现象:按照时间顺序,T1事务在t0时刻对row进行了修改(更新),T2事务在t1时刻先读取了被T1修改了的row的值,但是T1t2时刻回滚使得对row的修改失效。如果数据库引擎不支持因并发操作避免数据异常,则T2t1时刻读到的就是T1修改后的数据,但是这个数据在现实世界中不存在,对于事务T2而言,读取了被回滚掉的数据,即事务T2发生了脏读异常现象。

    对于不可重复读现象:事务T1t0时刻先读取row的旧值,事务T2t1时刻对row进行了修改(更新或删除)然后提交事务使得修改生效,此时row因更新变为了新值或因删除而不再存在。接下来,事务T1t3时刻再次读取row对象的值但是row的值已经是新值或者不存在了。对已事务T1而言,物是(同样是读row这个对象)人非(值已经和t0时刻读到的值不同),事务T1发生了不可重复读异常现象。

    对于幻象现象:事务T1t0时刻带有特定条件地读取了row对象的数据,事务T2t1时刻插入新的数据,新的数据满足与事务T1同样的条件,当事务T1t3时刻再次以同样的条件读取数据的时候,rows对象的值已经有新加入的行(因插入而比第一次读多出了数据)。对已事务T1而言,物是(同样是读row这个对象)人非(值已经和t0时刻读到的值不同),事务T1发生了幻象异常现象。幻象又被称为幻读,即第二次读操作读取了第一次读操作没有读到的rows(一行或多行)。

    在了解了SQL标准定义的三种异常现象后,回到我们在本节开始提出的问题:

    ACID的保护下,是不是数据就一定不会产生不一致的现象呢

    答案已经很明确:即使数据库系统提供ACID,除非我们使用“串行化(SERIALIZABLE)”隔离级别,否则数据在其他不同的隔离级别下还会产生数据不一致的现象。

    展开全文
  • 无规矩不成方圆,为了开发人员间更好的配合,我特意整理了这么一篇文档...接口规范定义 一、协议规范 为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS协议。为了确保数据交互安...

         无规矩不成方圆,为了开发人员间更好的配合,我特意整理了这么一篇文档供大家参考学习,如有意见、见解,请在评论区留言探讨。

         接口规范说起来大,其实也就那么几个部分,接口规范、接口管理工具、接口文档编写、开发文档编写

     

    接口规范定义

    一、协议规范

        为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS协议。为了确保数据交互安全,建议使用HTTPS协议。

     

    二、接口路径规范

        作为接口路径,为了方便清晰的区分来自不同的系统,可以采用不同系统/模块名作为接口路径前缀。

    格式规范如下:

        支付模块   /pay/xx

        订单模块  /order/xx

     

    三、版本控制规范

        为了便于后期接口的升级和维护,建议在接口路径中加入版本号,便于管理,实现接口多版本的可维护性。如果你细心留意过的话,你会发现好多框架对外提供的API接口中(如:Eureka),都带有版本号的。如:接口路径中添加类似"v1"、"v2"等版本号。

    格式规范如下:

          /xx/v1/xx

    更新版本后可以使用v2、v3等、依次递加。

     

    四、接口命名规范

        和Java命名规范一样,好的、统一的接口命名规范,不仅可以增强其可读性,而且还会减少很多不必要的口头/书面上的解释。

        可结合【接口路径规范】、【版本控制规范】,外加具体接口命名(路径中可包含请求数据,如:id等),建议具体接口命名也要规范些,可使用"驼峰命名法"按照实现接口的业务类型、业务场景等命名,有必要时可采取多级目录命名,但目录不宜过长,两级目录较为适宜。

    格式规范如下:

        /user/v1/sys/login     用户服务/模块的系统登录接口

       /zoo/v1/zoos/{ID}        动物园服务/模块中,获取id为ID的动物

     

    具体接口命名,通常有以下两种方式:

    • 接口名称动词前/后缀化

        接口名称以接口数据操作的动词为前/后缀,常见动词有:add、delete、update、query、get、send、save、detail、list等,如:新建用户addUser、查询订单详情queryOrderDetail。

    • 接口名称动词+请求方式

         接口路径中包含具体接口名称的名词,接口数据操作动作以HTTP请求方式来区分。常用的HTTP请求方式有:

        GET:从服务器取出资源(一项或多项)。

        POST:在服务器新建一个资源。

        PUT:在服务器更新资源(客户端提供改变后的完整资源)。

        PATCH:在服务器更新资源(客户端提供改变的属性)。

        DELETE:从服务器删除资源。

    如:

        GET /zoo/v1/zoos:列出所有动物园

        POST /zoo/v1/zoos:新建一个动物园

        GET /zoo/v1/zoos/{ID}:获取某个指定动物园的信息

        PUT /zoo/v1/zoos/{ID}:更新某个指定动物园的信息(提供该动物园的全部信息)

        PATCH /zoo/v1/zoos/{ID}:更新某个指定动物园的信息(提供该动物园的部分信息)

        DELETE /zoo/v1/zoos/{ID}:删除某个动物园

        GET /zoo/v1/zoos/{ID}/animals:列出某个指定动物园的所有动物

        DELETE /zoo/v1/zoos/ID/animals/ID:删除某个指定动物园的指定动物

     

    五、请求参数规范

    • 请求方式:

    按照GET、POST、PUT等含义定义,避免出现不一致现象,对人造成误解、歧义。

    • 请求头:

    请求头根据项目需求添加配置参数。如:请求数据格式,accept=‘application/json’等。如有需要,请求头可根据项目需求要求传入用户token、唯一验签码等加密数据。

    • 请求参数/请求体:

            请求参数字段,尽可能与数据库表字段、对象属性名等保持一致,因为保持一致最省事,最舒服的一件事。

     

    六、返回数据规范

        统一规范返回数据的格式,对己对彼都有好处,此处以json格式为例。返回数据应包含:返回状态码返回状态信息具体数据。

    格式规范如下:

    {
    
        "status":"000000",
    
        "msg":"success",
    
        "data": {
    
            //json格式的具体数据
    
        }
    
    }

            返回数据中的状态码、状态信息,常指具体的业务状态,不建议和HTTP状态码混在一起。HTTP状态,是用来体现 HTTP链路状态情况,如:404-Not Found。HTTP状态码和json结果中的状态码,并存尚可,用于体现不同维度的状态。

     

    接口管理工具推荐

        接口开发完后,最终的目的是提供给其他系统/模块来使用的,因此,接口的管理是必不可少的。

    接口管理的痛点

        接口的管理常常面临很多的痛苦,这里就列举几个常见的,看看你是否也遇到过。

    • 系统/模块太多、接口太多,没有系统统一管理所有接口。
    • 代码修改后,接口文档没有及时更新,造成接口文档和实际接口不一致的现象。
    • 接口管理系统自主研开发成本高。
    • 接口管理缺少接口mock功能。

    接口管理工具推荐

           在日常工作过程中用过、接触过的接口管理工具也是不尽其数,下面介绍你可能使用过、没有使用过的接口管理工具,同时也介绍这些接口管理工具的优缺点。   

    word

          相信大家之前用来管理接口比较多的应该是word吧,开发人员将系统的接口维护在word文档里,不管是组内沟通还是和其他团队的接口沟通都离不开这些接口文档,每次修改文档和代码都要同步修改。相信使用word的缺点大家应该也很清楚,就是维护和管理很麻烦,我们经常会遇到文档和代码不一致的情况,大部分不一致都是因为接口因为种种原因修改了,开发人员大部分都是只改了代码里的接口实现,而没有去修改接口文档。而且word文档搜索接口也很麻烦,没办法建全局索引,只能一个个文档点开查看,想想就很痛苦。但不可否认的是,word对于一些小团队用起来还是挺方便的,不用搭建系统,给谁一看就明白。

    自建接口管理系统

           对于一些有一定规模的企业,在各项工程管理活动上都非常正规,各种ISO标准要遵守,自然对接口管理的要求也非常高,之前在国有银行,我们就是自建了接口管理系统,自建还是很消耗人力成本的,从开发到后续运维,都要消耗人力,但是自建的好处就是,可以根据公司的要求进行各种花样的定制,我们之前在接口管理系统中加入了很多好用的定制功能,例如接口被哪些系统调用、接口是在哪个批次投产又在哪个批次做过变更等等,这对于架构师来说非常好用,用于分析接口影响范围非常方便。目前开源的接口管理系统还没有能做到这些定制化功能的。

    wiki

          之前在小团队的时候还用过一段时间的私有wiki,wiki特别适合于小团队高速线性迭代开发,在wiki上看到的就是最新的接口,团队内所有成员看到的都是一样的,如果接口有变化,相关开发人员修改后立即生效,保证了顺畅的接口沟通。但是wiki的缺点也很多,接口文档只是静态页面,无法实现一些动态效果,无法实现追溯等等缺点。

    RAP

           相信很多互联网公司都在使用RAP,RAP是阿里开源的一套接口管理系统,RAP可以比较方便的管理公司所有系统的接口,同时还有比较完善的权限管理,还可以做接口mock,方便开发人员在接口功能还没有完成的时候能够及时发布出去,给调用方去使用。但是RAP的缺点就是每个接口都需要维护进去,接口修改后也需要及时维护,当时我们在使用的时候遇到的最大的问题也是经常碰到接口没有及时维护的问题。

    swagger

          上面说的那些接口管理工具,其实都有一个很大的问题就是修改代码后需要同步维护接口文档,但是让程序员去修改文档是很难的,大部分程序员都比较讨厌维护各类文档。当我第一次了解到swagger的时候,发现这简直就是为程序员定制的接口管理工具,swagger定义了很多注解,在对接口加上swagger相关的注解,当接口代码修改后,swagger在工程启动后会根据代码自动生成最新的接口html文档,同时swagger提供了mock接口模拟的功能,也能够更加方便的模拟接口,并且还能够在swagger界面上直接发起接口调用,可以方便调用方在还没写代码的时候就能够尝试下接口调用后的结果。

          看了那么多swagger的优点,下面也说说swagger的缺点,那就是swagger是跟随着每个工程一起启动的,这就导致每个工程都有一个swagger的访问地址,如果公司系统很多的话,那就会导致查看不同系统的接口都要到不同的地址去查看,每个开发都要自己收藏好各个系统的swagger地址。有些公司也自己开发了统一网关,将所有swagger的接口地址聚合起来,但是多少还是涉及到一些开发工作的,而且做的还不一定很完善。

    Easy Mock

            官网的这张图基本上介绍清楚了easymock的核心功能,这其中我最看重的功能有两块,一个是能够集成swagger接口并集中管理所有接口,另一个就是响应式数据。

           EasyMock能够根据swagger接口的地址自动导入所有swagger接口,非常方便,对于非swagger的接口也可以手工维护进去,这样可以很方便的做到全公司接口统一维护,而且也有比较完善的接口权限管理,方便分组管理。但缺点就是过于庞大,可能太适合小一点项目或团队。

     

          上面提及到接口管理工具,大家可根据自己项目的规模、需求,进行实际选择,切记生搬硬套。

     

    欢迎微信扫码下面二维码,关注微信公众号【程序猿技术大咖】,进行更多交流学习!

    展开全文
  • HDMI接口定义,传输流程

    万次阅读 2019-06-12 16:45:10
    HDMI有A,B,C,D,E五种引脚类型,目前市面中比较常见的就是Type A: 其中 1-9 都是TMDS数据传输实际上用到的引脚,分为0,1,2三组 10-12 为TMDS时钟信号,如当前Video Timing为480p@60Hz(Htotal:800,Vtotal:525),...
  • Java基础常见笔试题总结

    万次阅读 多人点赞 2018-01-30 21:32:31
    以下是自己总结的一些Java常见的基础知识题,答案仅供参考,如有异议请指出。一直保持更新状态。 1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机...
  • 涉及诸如float或者double这两种浮点型数据的处理时,偶尔总会有一些怪怪的现象,不知道大家注意过没,举几个常见的栗子: 典型现象(一):条件判断超预期 System.out.println( 1f == 0.9999999f ); // 打印:false ...
  • xxx已经在obj中定义

    万次阅读 多人点赞 2019-07-11 14:57:32
    来看看常见的情况是什么: 1、头文件重复包含;2、变量重复定义 头文件重复包含 1.我们知道在编译c或c++程序时候,编译器首先要对程序进行预处理,预处理其中一项工作便是将你源程序中#include的头文...
  • 【缓存】缓存中常见的4种问题分析以及解决方案

    万次阅读 热门讨论 2017-10-08 09:15:54
    由于最近要准备换工作,同时最近在“Redis中国用户组”上关注了一系列Redis的活动,想要总结一下,Redis当做缓存使用过程中的一些常见问题。一、前提 1.文中相关术语 (1)缓存命中: 终端用户访问加速节点时,...
  • 二、源文件前加一个自己文件名的宏定义现象 三、函数声明时前面加不加extern 四、宏定义、结构体、typedef定义等位置 一、变量 一个全局变量到底是定义在头文件中,还是定义在源文件中? 结论:应该定义在.c...
  • 2,来源于配置(数据库配置,配置文件,操作系统配置等等)的不正常现象可以不作为缺陷提出,开发人员可以直接改正。恶果:相同的配置问题会不断重复,甚至于在用户处重复。3,人工回归测试,由于工期紧张,人力资源...
  • 如何进行软件缺陷等级定义

    千次阅读 2020-12-19 14:13:41
    接下来,测试人员要对Bug进行准确地描述,缺陷现象、产生条件等等都要描述清楚,同时也要给出合理的软件缺陷等级定义——这个软件缺陷处于哪个问题等级。今天主要想讨论下软件缺陷等级的问题。现有的国家军用标准中...
  • C潜规则篇之防止重定义

    千次阅读 2013-12-13 18:34:13
    C程序编译时常出现类似xxx redefinition错误,除了模块间的命名冲突(命名污染及static),问题多数与头文件管理有关。...这都可能导致类型或实体定义被重复包含和展开,使编译器抛出重定义错误。  解决
  • ==定义现象: 内网:即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的。但两个局域网内的内网IP可以有相同的。 外网:即互联网,局域网通过一台服务器...
  • [面试]-- 大数据常见面试题汇总(一)

    万次阅读 多人点赞 2016-06-06 13:47:33
    答案:结果查看监控日志,得知产生这种现象的原因是数据倾斜问题 解决: (1)调整拆分mapper的数量(partition数量) (2)增加jvm (3)适当地将reduce的数量变大 11、流API中的什么特性带来可以使map reduce任务...
  • IDL接口定义语言教程

    千次阅读 2013-07-02 11:36:57
    IDL接口定义语言   也叫“接口描述语言”(Interface Description Language),是一个描述软件组件接口的语言规范。 IDL用中立语言的方式进行描述,能使软件组件(不同语言编写的)间相互通信。 IDL通常用于RPC...
  • Android UI之开发——(1)、Android UI入门及常见属性与现象导读 :Android UI入门,对于很多人来讲都是比较简单的,教程也多如牛毛,但是这篇绝对和其他的不一样。从接触android开发就注定UI开发是一个一
  • 如何const定义一个不可变数组

    千次阅读 2018-07-16 15:08:47
    有个常见的面试题,我们知道,const是es6中新增用于定义常量。但是对于引用类型来说,const 所说的常量,是指,对应的指针或者说地址是常量。那么,如果我们要求,我们定义的数组里面的元素也是不可改变的呢?先来看...
  • dp的定义原理和dpi,ppi,px,pt,sp之间的区别

    万次阅读 多人点赞 2015-12-25 18:10:31
    你也可以查看我的其他同类文章,也会让你有一定的收货! 扩展知识: 4k是什么意思 1080p和720p是什么意思 百度百科分辨率中最后一段话不明白的,可以参考这里 在开始讲解dp前,先来认识一些...常见尺寸单位 px
  •  写程序时应该尽量避免同时获得多个锁,如果一定有必要这么做,则有一个原则:如果所有线程在需要多个锁时都按相同的先后顺序(常见的是按Mutex变量的地址顺序)获得锁,则不会出现死锁。比如一个程序中用到锁1、锁2、锁3...
  • 概率论几种常见分布

    千次阅读 2020-02-27 21:03:31
    概率论几种常见分布正态分布概要分析泊松分布适用范围伽玛分布对数正态分布 本文也算是一种对大学知识的回顾吧!学习数据分析看到几种统计方法,没办法,过来总计一下吧,反正感觉我以后用的次数还多着哩。 正态分布...
  • 初中常见的说明方法有哪些

    千次阅读 2020-12-30 18:46:54
    初中常见的说明方法有哪些2020-04-24 11:38:32文/颜雨常见的说明方法有举例子、打比方、下定义、列数字、作诠释、摹状貌等等,接下来分享具体的说明方法及例句,供参考。1.举例子:举出实际事例来说明事物,使所要...
  • 常见数据库知识总结 + 30个数据库常见面试题讲解

    万次阅读 多人点赞 2018-10-24 21:55:36
    常见数据库知识总结 MYAQL:事务:事务是并发控制的基本单元,事务是一个操作序列,要么都执行,要么都不执行,他是一个不可分割的工作单位,事务是维护数据库一致性的单位。 四个ACID基本性质: 1.原子性:要么...
  • 浅谈网络编程中的常见问题

    万次阅读 2019-08-27 17:43:47
    所以当一个socket连接中没有数据的传输,那么为了位置连续的连接需要发送心跳消息,具体心跳消息格式是开发者自己定义的。 9.TCP与UDP区别总结: 1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,...
  • C++编程常见错误整理

    千次阅读 2012-02-21 16:37:35
     (二) 一些常见的错误现象  1. 与变量有关的错误  (1)忘记定义变量;  (2)变量名命名不当;  (3)数据类型不一致;  (4)字符常量与字符串常量使用不当;  (5)输入输出的数据的类型与所用的...
  • CentOS7启动流程与常见故障修复

    千次阅读 2019-08-29 20:06:52
    重启,故障现象: 修复:救援模式,重新生成BootLoader chroot–>grub2-install /dev/sda(grub2-install依赖于系统根下的工具) 然后重启即可 CentOS 7 引导顺序 UEFi或BIOS初始化,运行POST开机自检 ...
  • 主瓣、栅瓣和旁瓣的定义

    万次阅读 多人点赞 2016-12-12 12:40:52
    发射天线的方向性可定义为:最大辐射密度/平均辐射密度,孔径效率越高越高,理想情况下要求其值等于1. 一般阵列天线都由两个或多个基本辐射源构成,也即是合成天线。每一个辐射源称作一个阵元。采用电子...
  • Keil编译常见问题

    千次阅读 2020-05-15 11:26:00
    Keil编译常见问题(一) .error: #18: 6.error: #18: expected a “)” 如果是出现在c文件中, 多半是因为少了一个")",或者错误行有编译器不识别的字符 如果出现在头文件中,错误行又是一个函数声明,多半是因为在函数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,812
精华内容 42,724
关键字:

常见现象的定义