精华内容
下载资源
问答
  • 点击上方“后端技术精选”,选择“置顶公众号”技术文章第一时间送达!作者:yizhiwaziwww.jianshu... 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的...

    点击上方“后端技术精选”,选择“置顶公众号”

    技术文章第一时间送达!

    作者:yizhiwazi

    www.jianshu.com/p/d160f2536de7

    序言:创建定时任务非常简单,主要有两种创建方式:一、基于注解(@Scheduled) 二、基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就大派用场了。

    一、静态定时任务(基于注解)

    基于注解来创建定时任务非常简单,只需几行代码便可完成。

    @Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。

    @Configuration //1.主要用于标记配置类,兼备Component的效果。
    @EnableScheduling // 2.开启定时任务
    public class SimpleScheduleConfig {
        //3.添加定时任务
        @Scheduled(cron = "0/5 * * * * ?")
        private void configureTasks() {
            System.err.println("执行定时任务1: " + LocalDateTime.now());
        }
    }
    

    Cron表达式参数分别表示:

    启动应用,可以看到控制台的信息如下:

    640?wx_fmt=png

    诚然,使用Scheduled 确实很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。

    二、动态定时任务(基于接口)

    为了演示效果,这里选用 Mysql数据库 和 Mybatis 来查询和调整定时任务的执行周期,然后观察定时任务的执行情况。

    1.引入依赖

        <!--依赖管理 -->
        <dependencies>
            <dependency><!--添加Web依赖 -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency><!--添加Mybatis依赖 -->
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency><!--添加MySql依赖 -->
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency><!--添加Test依赖 -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    2.添加数据库记录

    在Navicat 连接本地数据库,随便打开查询窗口,然后执行脚本内容,如下:

    DROP DATABASE IF EXISTS `socks`;
    CREATE DATABASE `socks`;
    USE `SOCKS`;
    DROP TABLE IF EXISTS `cron`;
    CREATE TABLE `cron`  (
      `cron_id` varchar(30),
      `cron` varchar(30) 
    );
    INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
    

    640?wx_fmt=png

    然后在项目中的application.yml 添加数据源:

    #application.yml 配置如下:
    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/socks?useSSL=false
        username: root
        password: root
    

    3.创建定时器

    数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。具体代码如下:

    @Configuration
    @EnableScheduling
    public class CompleteScheduleConfig implements SchedulingConfigurer {
    
        @Mapper
        public interface CronMapper {
            @Select("select cron from cron limit 1")
            String getCron();
        }
    
        @Autowired
        @SuppressWarnings("all")
        CronMapper cronMapper;
    
        /**
         * 执行定时任务.
         */
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            taskRegistrar.addTriggerTask(
                    //1.添加任务内容(Runnable)
                    () -> System.out.println("执行定时任务2: " + LocalDateTime.now().toLocalTime()),
                    //2.设置执行周期(Trigger)
                    triggerContext -> {
                        //2.1 从数据库获取执行周期
                        String cron = cronMapper.getCron();
                        //2.2 合法性校验.
                        if (StringUtils.isEmpty(cron)) {
                            // Omitted Code ..
                        }
                        //2.3 返回执行周期(Date)
                        return new CronTrigger(cron).nextExecutionTime(triggerContext);
                    }
            );
        }
    
    }
    

    4. 动态修改执行周期

    启动应用后,查看控制台,打印时间是我们预期的每5秒一次:

    640?wx_fmt=png

    然后打开Navicat ,将执行周期修改为每1秒执行一次,如图:

    640?wx_fmt=png

    查看控制台,发现执行周期已经改变,并且不需要我们重启应用,十分方便。如图:

    640?wx_fmt=png

    源码下载:

    https://github.com/yizhiwazi/springboot-socks/tree/master/springboot-schedule-task

    推荐阅读(点击即可跳转阅读)

    5. 

    展开全文
  • PHP动态函数执行与匿名函数执行

    千次阅读 2017-11-30 23:45:00
     * 动态函数执行与匿名函数执行\\ 技术QQ交流群:294088839  */ //动态函数执行 function a(){  echo 'a'; } function b(){  echo 'b'; } function c($c){  echo 'c';  $c(); } //C($_GET...
    <?php
    /**

     * 动态函数执行与匿名函数执行\\

    技术QQ交流群:294088839


     */
    //动态函数执行
    function a(){
        echo  'a';
    }
    function b(){
        echo 'b';
    }
    function c($c){
        echo 'c';
        $c();
    }
    //C($_GET['c']);
    echo '<hr>';
    //把一个函数名作为参数传进另一个函数中 然后调用相对应的函数
    // 例如 如果传过来个a 就会调用a函数从而输出a
    // 如果传过来一个PHP自带函数就会立刻执行  比如  phpinfo
    // 利用性不高


    // 匿名函数执行 也叫闭包函数  create_function这个匿名函数目前还没搞明白
    // 貌似通过这个函数可以关闭要触发的函数 从而执行些我们想要执行的代码
    // 有兴趣研究的可以探讨下
    $id=$_GET['id'];
    $str='echo  '.$a.'test'.$id.";";
    $la=create_function('$a',$str);
    //var_dump($la);
    /*$array=array('reall long string here,boy','this','midding length','larcet');
    usort($array,$la);*/

    //print_r($array);


    在PHP中使用create_function()创建匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给create_function()执行任意命令。

     
    以如下代码为例:
     
    <?php
    //how to exp this code
    $sort_by=$_GET[‘sort_by’];
    $sorter=’strnatcasecmp’;
    $databases=array(‘test’,’test’);
    $sort_function = ‘ return 1 * ‘ . $sorter . ‘($a[“‘ . $sort_by . ‘”], $b[“‘ . $sort_by . ‘”]);’;
    usort($databases, create_function(‘$a, $b’, $sort_function));
    ?>
    代码中$sort_by直接用$_GET取值未做过滤,create_function()中的函数体部分$sort_function只是简单的字符串拼接,利用注入将我们的代码写进去。
     
    这里我们首先测试将phpinfo();注入到create_function()的函数体部分$sort_function中。
     
    保存以上代码为func.php,然后提交func.php?sort_by=”]);}phpinfo();/*执行结果如图所示:
     
     
    如图所示phpinfo()函数执行了。
     
    在具体分析细节之前,先说一下create_function()。
     
    create_function返回一个字符串的函数名, 这个函数名的格式是:
     
    “\000_lambda_” . count(anonymous_functions)++
     
    我们来看看create_function的实现步骤:
     
    1. 获取参数, 函数体;
     
    2. 拼凑一个”function __lambda_func (参数) { 函数体;} “的字符串;
     
    3. eval;
     
    4. 通过__lambda_func在函数表中找到eval后得到的函数体, 找不到就出错;
     
    5. 定义一个函数名:”\000_lambda_” . count(anonymous_functions)++;
     
    6. 用新的函数名替换__lambda_func;
     
    7. 返回新的函数。
     
    实际上,create_functions是一个ZEND_FUNCTION,它被定义在./Zend/zend_builtin_functions.c中。
     
    eval_code = (char *) emalloc(eval_code_length);
     
    sprintf(eval_code, “function ” LAMBDA_TEMP_FUNCNAME “(%s){%s}”, Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code));
     
    eval_name = zend_make_compiled_string_description(“runtime-created function” TSRMLS_CC);
     
    retval = zend_eval_string(eval_code, NULL, eval_name TSRMLS_CC);
     
    可以看到这里只是简单利用zend_eval_string来生成匿名函数,此处”function ” LAMBDA_TEMP_FUNCNAME “(%s){%s}”,我们可以控制函数主体部分闭合前面的“{”,后面跟上我们的phpinfo()函数,将提交的参数sort_by=”]);}phpinfo();/*放到函数中去,如图所示:
     
     
    可以看到提交sort_by参数中的“}”闭合生成的匿名函数的“{”,所以这里的phpinfo()会被zend_eval_string执行。
     
    测试执行系统命令,如下所示:
     

     
    转自:https://www.t00ls.net/viewthread.php?tid=20774


    展开全文
  • JIT动态编译技术

    万次阅读 2020-08-25 16:11:47
    JIT动态编译技术 一个Java程序执行的过程,就是执行字节码指令的过程,一般这些指令会按照顺序一条一条指令解释执行,这种就是解释执行,解释执行的效率是非常低下的,因为需要先将字节码翻译成机器码,才能执行。 ...

    JIT动态编译技术

    一个Java程序执行的过程,就是执行字节码指令的过程,一般这些指令会按照顺序一条一条指令解释执行,这种就是解释执行,解释执行的效率是非常低下的,因为需要先将字节码翻译成机器码,才能执行。

    而那些被频繁调用的代码,比如调用次数很高或者for循环次数很多的那些代码,称为热点代码,如果按照解释执行,效率是非常低下的。

    为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器,就称为即时编译器(Just In Time Compiler),简称JIT编译器。这些被编译后的机器码会被缓存起来,以备下次使用,但对于那些执行次数很少的代码来说,这种编译动作就纯属浪费。

    即时编译器类型

    在HotSpot虚拟机中,内置了两个JIT,分别为C1编译器和C2编译器。

    • C1编译器:是一个简单快速的编译器,主要的关注点在于局部性的优化,适用于执行时间较短或对启动性能有要求的程序,例如,GUI应用对界面启动速度就有一定要求,C1也被称为Client Compiler。
    • C2编译器:是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序,C2也被称为Server Compiler。

    热点代码

    热点代码有两类:

    1. 被多次调用的方法。
    2. 被多次执行的循环体。

    JIT即时编译后的机器码都会放在CodeCache里,JVM提供了一个参数-XX:ReservedCodeCacheSize用来限制CodeCach的大小。如果这个空间不足,JIT就无法继续编译,编译执行会变成解释执行,性能会降低一个数量级。同时,JIT编译器会一直尝试去优化代码,从而造成了CPU占用上升。

    # java -XX:+PrintFlagsFinal -version | grep ReservedCodeCacheSize
        uintx ReservedCodeCacheSize                     = 251658240                           {pd product}
    java version "1.8.0_151"
    

    -XX:ReservedCodeCacheSize默认大小为240M。

    热点探测

    J9使用过采样的热点探测技术,但是缺点是很难精确的确认一个方法的热度。

    在HotSpot虚拟机中采用基于计数器的热点探测,为每个方法建立一个计数器,用于统计方法的执行次数,如果执行次数超过一定的阈值就认为它是“热点方法”。

    虚拟机为每个方法准备了两类计数器:方法调用计数器和回边计数器(Back Edge Counter)。

    方法调用计数器

    方法调用计数器(Invocation Counter):用于统计方法被调用的次数,默认阈值在客户端模式下是1500次,在服务端模式下是10000次,可通过-XX: CompileThreshold来设定。

    先来看一下运行模式:

    # java -version
    java version "1.8.0_151"
    Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
    

    从上面的输出可以看出jdk8中默认的运行模式为Server VM

    再来看一下阈值的默认值:

    # java -XX:+PrintFlagsFinal -version | grep CompileThreshold
         intx CompileThreshold                          = 10000                               {pd product}
    

    回边计数器

    回边计数器(Back Edge Counter):用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流在循环边界往回跳转的指令称为“回边”(Back Edge)。

    虚拟机运行在服务端模式下,回边计数器的阈值计算公式为方法调用计数器阈值(CompileThreshold)*(OSR 比率(OnStackReplacePercentage)- 解释器监控比率(InterpreterProfilePercentage)/ 100。

    其中OnStackReplacePercentage默认值为140,InterpreterProfilePercentage默认值为33,如果都取默认值,那Server模式虚拟机回边计数器的阈值为10000*(140-33)/100=10700。

    intx CompileThreshold                          = 10000                               {pd product}
    intx InterpreterProfilePercentage              = 33                                  {product}
    intx OnStackReplacePercentage                  = 140                                 {pd product}
    

    建立回边计数器的主要目的是为了触发OSR(On StackReplacement)编译,即栈上编译。在一些循环周期比较长的代码段中,当循环达到回边计数器阈值时,JVM会认为这段是热点代码,JIT编译器就会将这段代码编译成机器码并缓存,在该循环时间段内,会直接将执行代码替换,执行缓存中的机器码。

    分层编译

    在Java8中,默认开启分层编译。可以通过java -version命令查看到当前系统使用的编译模式。

    # java -version
    java version "1.8.0_151"
    Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
    

    mixed mode为分层编译。

    使用-Xint参数强制虚拟机运行于只有解释器的编译模式下:

    # java -Xint -version
    java version "1.8.0_151"
    Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, interpreted mode)
    

    使用-Xcomp参数强制虚拟机运行于只有解释器的编译模式下:

    # java -Xcomp -version
    java version "1.8.0_151"
    Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, compiled mode)
    

    分层编译根据编译器编译、优化的规模和耗时,划分出5个不同的层次:

    • 第0层:程序纯解释执行,并且解释器不开启性能监控功能(Profiling)。
    • 第1层:使用C1将字节码编译为本地代码,进行简单、可靠的优化,不开启Profiling。
    • 第2层:仍然使用C1编译,仅开启方法调用计数器和回边计数器等Profiling。
    • 第3层:仍然使用C1编译,开启全部Profiling。
    • 第4层:使用C2将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

    在不启用分层编译的情况下,当方法的调用次数和循环回边的次数总和,超过由参数-XX:CompileThreshold指定的阈值时,便会触发即时编译;当启用分层编译时,这个参数将会失效,会采用动态调整的方式进行。

    编译优化技术

    JIT编译运用了一些经典的编译优化技术来实现代码的优化,即通过一些例行检查优化,可以智能地编译出运行时的最优性能代码。

    方法内联

    方法内联的优化行为就是把目标方法的字节码复制到发起调用的方法之中,避免发生真实的方法调用,这样就减少了虚拟机栈中一次栈帧的入栈和出栈。

    C2编译器会在解析字节码的过程中完成方法内联。内联后的代码和调用方法的代码,会组成新的机器码,存放在CodeCache区域里。

    另外,C2支持的内联层次不超过9层,太高的话,CodeCache区域会被挤爆,这个阈值可以通过-XX:MaxInlineLevel进行调整。相似的,编译后的代码超过一定大小也不会再内联,这个参数由-XX:InlineSmallCode进行调整。有非常多的参数,被用来控制对内联方法的选择,整体来说,短小精悍的小方法更容易被优化。

    例如以下方法:

        private int add1(int x1, int x2, int x3, int x4) {
            return add2(x1, x2) + add2(x3, x4);
        }
        private int add2(int x1, int x2) {
            return x1 + x2;
        }
    

    最终会被优化为:

        private int add(int x1, int x2, int x3, int x4) {
            return x1 + x2+ x3 + x4;
        }
    

    下面通过一段代码来演示方法内联的过程:

    public class CompDemo {
        private int add1(int x1, int x2, int x3, int x4) {
            return add2(x1, x2) + add2(x3, x4);
        }
        private int add2(int x1, int x2) {
            return x1 + x2;
        }
    
        public static void main(String[] args) {
            CompDemo compDemo = new CompDemo();
            //方法调用计数器的默认阈值10000次,我们循环遍历超过需要阈值
            for(int i=0; i<1000000; i++) {
                compDemo.add1(1,2,3,4);
            }
    
        }
    }
    

    设置VM参数:-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining

    • -XX:+PrintCompilation:在控制台打印编译过程信息。
    • -XX:+UnlockDiagnosticVMOptions:解锁对JVM进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对JVM进行诊断。
    • -XX:+PrintInlining:将内联方法打印出来。

    运行结果如下:

    ...
        159   29 %     4       com.morris.jvm.jit.CompDemo::main @ 10 (32 bytes)
                                  @ 21   com.morris.jvm.jit.CompDemo::add1 (15 bytes)   inline (hot)
                                    @ 3   com.morris.jvm.jit.CompDemo::add2 (4 bytes)   inline (hot)
                                    @ 10   com.morris.jvm.jit.CompDemo::add2 (4 bytes)   inline (hot)
    ...
    

    方法最后面有个hot关键字,说明已经触发了方法内联。

    通过JITWatch工具也能发现触发了方法内联:

    在这里插入图片描述
    在这里插入图片描述
    如果将循环次数减少至1000次,就不会触发方法内联了,修改后的运行结果如下:

    ....
        116   26       3       com.morris.jvm.jit.CompDemo::add2 (4 bytes)
        116   27       3       com.morris.jvm.jit.CompDemo::add1 (15 bytes)
                                  @ 3   com.morris.jvm.jit.CompDemo::add2 (4 bytes)
                                  @ 10   com.morris.jvm.jit.CompDemo::add2 (4 bytes)
    

    热点方法的优化可以有效提高系统性能,一般我们可以通过以下几种方式来提高方法内联:

    • 通过设置JVM参数来减小热点阈值,以便更多的方法可以进行内联,但这种方法意味着需要占用更多地内存。
    • 在编程中,避免在一个方法中写大量代码,习惯使用小方法体。

    锁消除

    在不需要保证线程安全的情况下,尽量不要使用线程安全容器,比如StringBuffer,由于StringBuffer中的append()方法被synchronized关键字修饰,会使用到锁,从而导致性能下降。

    但实际上,在以下代码测试中,StringBuffer和StringBuilder的性能基本没什么区别。这是因为在局部方法中创建的对象只能被当前线程访问,无法被其它线程访问,这个变量的读写肯定不会有竞争,这个时候JIT编译会对这个对象的方法锁进行锁消除。

    public class UnLock {
        public static void main(String[] args) {
            long timeStart1 = System.currentTimeMillis();
            for (int i = 0; i < 10000000; i++) {
                testStringBuffer("aaaaa", "bbbbb");
            }
            long timeEnd1 = System.currentTimeMillis();
            System.out.println("StringBuffer cost: " + (timeEnd1 - timeStart1) + "(s)");
    
            long timeStart2 = System.currentTimeMillis();
            for (int i = 0; i < 10000000; i++) {
                testStringBuilder("aaaaa", "bbbbb");
            }
            long timeEnd2 = System.currentTimeMillis();
            System.out.println("StringBuilder cost: " + (timeEnd2 - timeStart2) + "(s)");
        }
    
        public static void testStringBuffer(String s1, String s2) {
            StringBuffer sb = new StringBuffer();
            sb.append(s1);
            sb.append(s2);
        }
    
        public static void testStringBuilder(String s1, String s2) {
            StringBuilder sd = new StringBuilder();
            sd.append(s1);
            sd.append(s2);
        }
    }
    

    运行结果如下:

    StringBuffer cost: 229(s)
    StringBuilder cost: 190(s)
    

    当我们把锁消除(-XX:-EliminateLocks)关闭后,运行结果如下:

    StringBuffer cost: 570(s)
    StringBuilder cost: 148(s)
    

    锁消除关闭后测试发现性能差别有点大。

    -XX:+EliminateLocks:开启锁消除(jdk1.8 默认开启)。

    -XX:-EliminateLocks:关闭锁消除

    逃逸分析与标量替换

    通过逃逸分析(Escape Analysis),JVM能够分析出一个新对象的使用范围,从而决定是否要将这个对象分配到堆上。

    对象的三种逃逸状态:

    • GlobalEscape(全局逃逸):一个对象的引用逃出了方法或者线程。例如,一个对象的引用是复制给了一个类变量,或者存储在在一个已经逃逸的对象当中,或者这个对象的引用作为方法的返回值返回给了调用方法。
    • ArgEscape(参数逃逸):在方法调用过程中传递对象的引用给调用方法。
    • NoEscape(没有逃逸):该对象只在本方法中使用,未发生逃逸。

    下面用一段代码来说明对象的三种逃逸状态:

    package com.morris.jvm.gc;
    
    /**
     * 演示逃逸分析的三种状态
     * 1. 全局逃逸
     * 2. 参数逃逸
     * 3. 没有逃逸
     */
    public class EscapeStatus {
    
        private B b;
    
        /**
         * 给全局变量赋值,发生逃逸(GlobalEscape)
         */
        public void globalVariablePointerEscape() {
            b = new B();
        }
    
        /**
         * 方法返回值,发生逃逸(GlobalEscape)
         */
        public B methodPointerEscape() {
            return new B();
        }
    
        /**
         * 实例引用传递,发生逃逸(ArgEscape)
         */
        public void instancePassPointerEscape() {
            methodPointerEscape().printClassName(this);
        }
    
        /**
         * 没有发生逃逸(NoEscape)
         */
        public void noEscape() {
            Object o = new Object();
        }
    }
    
    class B {
        public void printClassName(EscapeStatus escapeStatus) {
            System.out.println(escapeStatus.getClass().getName());
        }
    }
    

    可以用JVM参数-XX:+DoEscapeAnalysis来开启逃逸分析,JDK8默认开启。

    逃逸分析的性能测试:

    package com.morris.jvm.gc;
    
    /**
     * 演示逃逸分析的标量替换
     * VM args:-Xmx50m -XX:+PrintGC -XX:-DoEscapeAnalysis --> 682ms+大量的GC日志
     * VM args:-Xmx50m -XX:+PrintGC --> 4ms,无GC日志
     */
    public class EscapeAnalysisDemo {
    
        public static void main(String[] args) {
    
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1_0000_0000; i++) {
                allocate();
            }
            System.out.println((System.currentTimeMillis() - start) + " ms");
        }
    
        private static void allocate() {
            new Person(18, 120.0);
        }
    
        private static class Person {
            int age;
            double weight;
    
            public Person(int age, double weight) {
                this.age = age;
                this.weight = weight;
            }
        }
    
    }
    

    使用jvm参数-Xmx50m -XX:+PrintGC -XX:-DoEscapeAnalysis运行程序耗时682ms,控制台会打印大量的GC日志。

    使用jvm参数-Xmx50m -XX:+PrintGC运行程序耗时4ms,控制台没有打印GC日志,也就是没有发生GC。由此可以发现开启逃逸分析后,对象分配的性能显著提升。

    标量:一个数据无法再分解为更小的数据来表示,Java中的基本数据类型byte、short、int、long、boolean、char、float、double以及reference类型等,都不能再进一步分解了,这些就可以称为标量。

    标量替换:如果一个对象只是由标量属性组成,那么可以用标量属性来替换对象,在栈上分配。

    例如上面的Persion只是由int和double类型的属性构成,可以进行标量替换,替换后变成类似如下的代码:

        private static void allocate() {
            int age = 18;
            double weight = 120.0;
        }
    

    变成上面的代码后,这样基本数据类型就可以在栈上分配了。

    而下面的Person类无法进行标量替换,只能在堆上分配了:

        private static class Person {
            byte[] bytes = new byte[1024]; // 不是标量
            String name;
            int age;
        }
    

    -XX:+EliminateAllocations:开启标量替换(jdk1.8 默认开启)。

    -XX:-EliminateAllocations:关闭标量替换。

    展开全文
  • 符号执行技术总结(A Brief Summary of Symbol Execution)Prologue摘要简介经典符号执行技术现代符号执行技术混合执行测试(Concolic testing)执行生成测试(Execution-Generated Testing (EGT))动态符号执行中的...

    Prologue

    近期查阅了符号执行的经典文章(Symbolic Execution for Software Testing: Three Decades Later),整理部分资料如下。(之前还读过ICSE2018的Towards Optimal Concolic Testing

    Recommended reading
    [1] King J C. Symbolic execution and program testing[J]. Communications of the ACM, 1976, 19(7): 385-394.
    https://yurichev.com/mirrors/king76symbolicexecution.pdf
    [2] Cadar C, Sen K. Symbolic execution for software testing: three decades later[J]. Communications of the ACM, 2013, 56(2): 82-90.
    https://people.eecs.berkeley.edu/~ksen/papers/cacm13.pdf
    [3] Baldoni R, Coppa E, D’elia D C, et al. A survey of symbolic execution techniques[J]. ACM Computing Surveys (CSUR), 2018, 51(3): 50.
    https://dl.acm.org/citation.cfm?id=3182657

    Lecture
    1.Symbolic Execution Lecture at Harvard.
    https://www.seas.harvard.edu/courses/cs252/2011sp/slides/Lec13-SymExec.pdf
    2.Symbolic Execution Lecture at Iowa State University.
    http://web.cs.iastate.edu/~weile/cs641/9.SymbolicExecution.pdf
    3.Symbolic Execution Lecture at University of Maryland.
    https://www.cs.umd.edu/class/spring2013/cmsc631/lectures/symbolic-exec.pdf

    Video
    Symbolic Execution Lecture at MIT.
    https://www.youtube.com/watch?v=mffhPgsl8Ws
    Symbolic Execution Lecture (part of Software Security course on Coursera).
    https://www.coursera.org/learn/software-security/lecture/agCNF/introducing-symbolic-execution

    摘要

    在过去的40年中,人们对软件测试的符号执行产生了极大的兴趣,因为它能够生成高覆盖率的测试套件并在复杂的软件应用程序中发现深层次的错误。符号执行已经在数十种开发工具中孵化,从而在许多突出的软件可靠性应用中取得重大的实际突破。

    许多安全和软件测试应用程序需要检查程序的某些属性是否适用于任何可能的使用场景。例如,识别软件漏洞的工具可能需要排除任何后门的存在,以绕过程序的身份验证。一种方法是使用不同的,可能是随机的输入来测试程序。由于后门可能只针对非常具体的程序工作负载,因此自动探索可能的输入空间至关重要。符号执行通过同时系统地探索许多可能的执行路径,在不需要具体输入的情况下,为问题提供了一个优雅的解决方案。该技术不是采用完全指定的输入值,而是抽象地将它们表示为符号,使用约束解算器来构造可能导致属性冲突的实际实例。

    本文概述了现代符号执行技术,讨论了它们在路径探索、约束解决和内存建模方面面临的主要挑战,并讨论了主要从作者自己的工作中得出的几种解决方案。

    简介

    符号执行作为一种生成高覆盖测试套件和在复杂软件应用中发现深层错误的有效技术,引起了人们的广泛关注。符号执行是一种流行的程序分析技术,在70年代中期引入,用于测试某个软件是否可以违反某些属性。本文概述了现代符号执行技术,并从路径探索、约束解决和内存建模方面讨论了它们的挑战。请注意,本文并不打算在这里提供对该领域现有工作的全面调查,而是选择使用简明的示例来说明一些关键挑战和建议的解决方案。有关符号执行技术的详细概述,我们将读者引见之前在该领域发布的调查(A survey of symbolic execution techniques)[3].

    定义
    符号执行 (Symbolic Execution)是一种程序分析技术,它可以通过分析程序来得到让特定代码区域执行的输入。顾名思义,使用符号执行分析一个程序时,该程序会使用符号值作为输入,而非一般执行程序时使用的具体值。在达到目标代码时,分析器可以得到相应的路径约束,然后通过约束求解器来得到可以触发目标代码的具体值。

    目标
    软件测试中的符号执行主要目标是: 在给定的探索尽可能多的、不同的程序路径(program path)。对于每一条程序路径,(1) 生成一个具体输入的集合(主要能力);(2) 检查是否存在各种错误,包括断言违规、未捕获异常、安全漏洞和内存损坏。

    生成具体测试输入的能力是符号执行的主要优势之一:从测试生成的角度来看,它允许创建高覆盖率的测试套件,而从bug查找的角度来看,它为开发人员提供了触发bug的具体输入,该输入可用于确认和调试打开的错误。生成它的符号执行工具的数据。

    此外,请注意,在查找给定程序路径上的错误时,符号执行比传统的动态执行技术(如由Valgrind或Purify等流行工具实现的技术)更强大,这取决于触发错误的具体输入的可用性。最后,与某些其他程序分析技术不同,符号执行不仅限于查找诸如缓冲区溢出之类的一般性错误,而且可以导致更高级别的程序属性,例如复杂的程序断言。

    我们从一个简单的例子开始,它强调了本文其余部分所讨论的许多基本问题。
    在这里插入图片描述
    考虑上图的C语言代码,并假设我们的目标是确定哪些输入使函数foobar的第8行的断言失败。 由于每个4字节输入参数可以采用多达2 ^ 32个不同的整数值,因此在随机生成的输入上具体运行foobar的方法不太可能准确地获取断言失败的输入。 通过使用符号作为其输入而不是具体值来评估代码,符号执行克服了这种限制,并且可以推断输入类而不是单个输入值。更详细地,通过代码的静态分析不能确定的每个值,例如函数的实际参数或从流中读取数据的系统调用的结果,由符号αi表示。 在任何时候,符号执行引擎都维持一个状态(stmt,σ,π)。

    1. stmt是下一个要评估的语句。 目前,我们假设stmt可以是赋值,条件分支或跳转。
    2. σ是一个符号存储,它将程序变量与具体值或符号值αi上的表达式相关联。
    3. π表示路径约束,即,是表示由于在执行中为了达到stmt而采取的分支而对符号αi的一组假设的公式。 在分析开始时,π=真。
      在这里插入图片描述
      函数foobar的符号执行,可以有效地表示为树,如下图所示。
      在这里插入图片描述
      在这里插入图片描述

    经典符号执行技术

    符号执行的主要思想就是将输入(input)用符号来表征而不是具体值,同时将程序变量表征成符号表达式。因此,程序的输出就会被表征成一个程序输入的函数,即fun(input)。在软件测试中,符号执行被用于生成执行路径(execution path)的输入。在具体的执行过程中,程序在特定的输入上运行,并对单个控制流路径进行了探索。因此,在大多数情况下,具体的执行只能在对相关财产进行近似分析的情况下进行。相反,符号执行可以同时探索程序在不同输入下可能采用的多种路径。这为可靠的分析铺平了道路,可以对检查的属性产生强有力的保证。关键思想是允许程序采用符号而不是具体的输入值。

    执行路径(execution path):一个true和false的序列seq={p0,p1,…,pn}。其中,如果是一个条件语句,那么pi=ture则表示这条条件语句取true,否则取false。
    执行树(execution tree):一个程序的所有执行路径则可表征成一棵执行树。

    例如,图1中的函数testme()有三个执行路径,形成了图2所示的执行树。

    在这里插入图片描述
    在这里插入图片描述

    3条不同的执行路径构成了一棵执行树。三组输入{x=0,y=1},{x=2,y=1},{x=30,y=15}覆盖了所有的执行路径。

    符号状态(symbolic state):符号执行维护一个符号状态e,它将变量映射到符号表达式。
    符号路径约束(symbolic path constraint):符号路径约束PC,它是符号表达式上无量词的一阶公式。

    符号执行后的结果如下图所示:e和PC都在符号执行过程中更新。 在沿着程序的执行路径的符号执行结束时,使用约束求解器来求解PC以生成具体的输入值。如果程序在这些具体的输入值上执行,它将采用与符号执行完全相同的路径并以相同的方式终止。例如,图1中代码的符号执行以空符号状态开始,符号路径约束为true。执行过程中的状态如图中红色部分所示。

    在这里插入图片描述

    如果符号执行实例命中退出语句或错误(例如,程序崩溃或违反断言),则终止符号执行的当前实例并且生成对当前符号路径约束的令人满意的分配,使用现成的约束求解器。 令人满意的赋值形成了测试输入:如果程序是在这些具体的输入值上执行的,它将采用与符号执行完全相同的路径并以相同的方式终止。

    当代码中包含循环和递归时,如果终止条件是符号的话,那么符号执行会产生无限数量的执行路径。例如下图所示,

    在这里插入图片描述

    如果循环或递归的终止条件是符号的,则包含循环或递归的代码的符号执行可能导致无限数量的路径。 例如,图3中的代码具有无限数量的执行路径,这个时候,符号路径要么就是一串有限长度的ture后面跟着一个false(跳出循环),要么就是无限长的true。如图所示,
    在这里插入图片描述
    在实践中,需要对搜索施加限制,例如超时,或对路径数量,循环迭代或探索深度的限制。

    符号执行的主要缺点:如果符号路径约束不可解(不能被solver解决)或者是不能被高效(时间效率)的解,则不能生成input。回到之前的例子,如果把函数twice改成(v*v)%50(非线性):假设采用的sovler不可解非线性约束,那么,符号执行将失败,即无法生成input。假设twice函数是第三方库函数,没有解释,那么约束求解器也无法对其进行求解。由于约束求解器无法解决这些约束中的任何一个,符号执行将无法为修改后的程序生成任何输入。接下来,我们将描述两种现代符号执行技术,它们可以缓解这个问题,并为修改后的程序生成至少一些输入。

    在这里插入图片描述

    现代符号执行技术

    现代符号执行技术的关键要素之一是它们混合具体(Concrete)执行和符号(Symbolic)执行的能力。 我们在下面介绍两个这样的扩展,然后讨论它们提供的关键优势。
    在这里插入图片描述

    混合执行测试(Concolic testing)

    当给定若干个具体的输入时,Concolic testing动态地执行符号执行。Concolic testing会同时维护两个状态:

    精确状态(concrete state): maps all variables to their concrete values.
    符号状态(symbolic state): only maps variables that have non-concrete values.

    不同于传统的符号执行技术,由于Concolic testing需要维护程序执行时的整个精确状态,因此它需要一个精确的初始值。举例说明,还是之前这个例子:对于图1中的示例,concolic执行将生成一些随机输入,比如{ x = 22; y = 7} 并具体和象征性地执行程序。具体执行将在第7行采用“else”分支,符号执行将沿具体执行路径生成路径约束 x0 != 2y0。Concolic测试否定路径约束中的合取并解决x0 = 2y0以获得测试输入{x = 2; y = 1}; 执行采用与前一个不同的路径 - 第7行的“then”分支,现在在此执行中获取第8行的“else”分支。与前面的执行一样,concolic测试也沿着这个具体的执行执行符号执行,并生成路径约束。Concolic测试将生成一个新的测试输入,强制程序以及之前未执行的执行路径。在第三次执行程序之后,concoic测试报告已经探索了程序的所有执行路径并终止了测试输入生成。
    在这里插入图片描述

    执行生成测试(Execution-Generated Testing (EGT))

    由EXE和KLEE工具实施和扩展的EGT方法的工作原理是区分程序的具体和符号状态。EGT在执行每个操作之前,检查每个相关的值是精确的还是已经符号化了的,然后动态地混合精确执行和符号执行。如果所有的相关值都是一个实际的值(即精确的,concrete),那么,直接执行原始程序(即,操作,operation)。否则(至少一个值是符号化的),这个操作将会被符号执行。举例说明,假设之前那个例子,第17行改成y=10。那么,在调用twice时,传入的参数是concrete的,返回的也是一个concrete value,因此z也是一个concrete value。第7、8行中的z和y+10也会被转换成concrete vaule。然后再进行符号执行。
    在这里插入图片描述
    Concoic测试和EGT是现代符号执行技术的两个实例,其主要优势在于它们混合具体和符号执行的能力。 为简单起见,在本文的其余部分,我们将这些技术统称为“动态符号执行”。

    动态符号执行中的不精确性(imprecision) vs.完整性(completeness)

    不精确性: 代码调用了第三方代码库(由于种种原因无法进行代码插装),假设传入的参数都是concrete value,那么就像EGT中的一样,可以全部当作concrete execution。即使传入的参数中包含符号,动态符号执行还是可以对符号设一个具体的值。Concolic和EGT有不同的解决方法,后面再介绍。除了调用外部代码,对于难以处理的操作数(如浮点型)或是一些复杂的函数(solver无法解决或需要耗费大量时间),使用concrete value可以帮助符号执行环节这种impression。

    完备性: 动态符号执行通过concrete value可以简化约束,从而防止符号执行get stuck。但是这也会带来一个新问题,就是由于这种简化,它可能会导致一些不完整性,即有时候无法对所有的execution path都能生成input。但是,当遇到不支持的操作或外部调用时,这显然优于简单地中止执行。

    动态符号执行使用具体值简化约束的能力有助于为符号执行卡住的执行路径生成测试输入,但这需要注意:由于简化,它可能会失去完整性,即它们可能无法生成测试 某些执行路径的输入。 例如,在我们的示例中,动态符号执行将无法为路径true,false生成输入。 但是,当遇到不支持的操作或外部调用时,这显然优于简单地中止执行。

    主要挑战和解决方案

    接下来我们将讨论符号执行中的关键挑战,以及为响应它们而开发的一些有趣的解决方案。

    路径爆炸(Path Explosion)

    描述:
    首先,要知道,符号执行implicitly过滤两种路径:
    不依赖于符号输入的路径;
    对于当前的路径约束,不可解的路径。
    但是,尽管符号执行已经做了这些过滤,路径爆炸依旧是符号执行的最大挑战。

    解决方案:

    1. 利用启发式搜索搜索最佳路径
      目前,主要的启发式搜索主要focus在对语句和分支达到高覆盖率,同时他们也可被用于优化理想的准则。
      方法1:利用控制流图来guideexporation。
      方法2:interleave 符号执行和随机测试。
      方法3(more recently):符号执行结合演化搜索(evolutionary search)。其中,fitness function用于drive the exploration of the input space。
    2. 利用可靠的(sound)程序分析技术来减小路径爆炸的复杂度
      方法1:静态地合并路径,然后再feed solver。尽管这个方法在很多场合都有效,但是他把复杂度转移给了solver,从而导致了下一个challenge,即约束求解的复杂度。
      方法2: 在后续的计算中,记录并重用low-level function的分析结果。
      方法3 : 自动化剪枝

    约束求解(Constraint Solving)

    描述:
    约束求解是符号执行的技术瓶颈。因此,对于solver的优化(提高solver的求解能力)成了解决这个技术瓶颈的手段。

    解决方案:

    1. 去除不相关的约束
      一般来说,程序分支主要依赖于一小部分的程序变量。也就是说,程序分支依赖于一小部分来自于路径条件(path condition)的约束。因此,一种有效的方法就是去掉那些与当前分支的输出不相关的路径条件。例如,现有路径条件:(x+y>10)(z>0)(y<12)(z-x=0)。假设我们现在想生成满足(x+y>10)(z>0)^¬(y<12),其中我们想建立对¬(y<12)(与y有关)的feasibility。那么,(z>0)和(z-x=0)这两个约束都可以去掉,因为与y不相关。
    2. 递增求解
      核心思想就是缓存已经求解过的约束,例如(x+y<10)^(x>5)=>{x=6,y=3}。对于新的约束,首先判断这个新约束的搜索空间是缓存里约束的超集还是子集。如果是新的约束的搜索空间是缓存的约束的子集,那么,就把缓存中的约束去掉多余的条件后继续求解。如果是超集,那么直接把解代入去验证。

    内存建模(Memory Modeling)

    描述:
    程序语句转化成符号约束的精度对符号执行的覆盖率有很大的影响。例如,内存建模是用一个具体的数值去近似一个固定位数的整数变量可能会很有效,但是另一方面,它也会导致imprecision,比如丢失一些符号执行的路径,或探索一些无用的解。另一个例子就是指针,一些工具如DART[3]只能处理精确的指针。

    解决方案:
    precision和scalability是一个trade-off。需要考虑的因素有:
    a) 代码是high level的application code还是low-level的system code。
    b) 不同的约束求解器的实际效果。

    并发控制(Handling Concurrency)

    描述:
    大型真实世界的节目通常是并发的。 由于这些程序固有的非确定性(non-deteminism),测试是非常困难的。 尽管存在这些挑战,但动态符号执行已经有效地用于测试并发程序,包括具有复杂数据输入,分布式系统和GPGPU程序的应用程序。

    符号执行工具

    动态符号执行已经由学术界和研究实验室的几个工具实现。 这些工具支持多种语言,包括C / C ++,Java和x86指令集,实现几种不同的内存模型,针对不同类型的应用程序,并使用几种不同的约束求解器和理论。

    Java

    • JPF-Symbc - Symbolic execution tool built on Java PathFinder. Supports multiple constraint solvers, lazy initialization, etc.
    • JDart - Dynamic symbolic execution tool built on Java PathFinder. Supports multiple constraint solvers using JConstraints.
    • CATG - Concolic execution tool that uses ASM for instrumentation. Uses CVC4.
    • LimeTB - Concolic execution tool that uses Soot for instrumentation. Supports Yices and Boolector. Concolic execution can be distributed.
    • Acteve - Concolic execution tool that uses Soot for instrumentation. Originally for Android analysis. Supports Z3.
    • jCUTE - Concolic execution tool that uses Soot for instrumentation. Supports lp_solve.
    • JFuzz - Concolic execution tool built on Java PathFinder.
    • JBSE - Symbolic execution tool that uses a custom JVM. Supports CVC3, CVC4, Sicstus, and Z3.
    • Key - Theorem Prover that uses specifications written in Java Modeling Language (JML).

    LLVM

    • KLEE - Symbolic execution engine built on LLVM.
    • Cloud9 - Parallel symbolic execution engine built on KLEE.
    • Kite - Based on KLEE and LLVM.

    .NET

    • PEX - Dynamic symbolic execution tool for .NET.

    C

    • CREST.
    • Otter.
    • CIVL - A framework that includes the CIVL-C programming language, a model checker and a symbolic execution tool.

    JavaScript

    Python

    • PyExZ3 - Symbolic execution of Python functions. A rewrite of the NICE project’s symbolic execution tool.

    Ruby

    • Rubyx - Symbolic execution tool for Ruby on Rails web apps.

    Android

    Binaries

    • Mayhem.
    • SAGE - Whitebox file fuzzing tool for X86 Windows applications.
    • DART.
    • BitBlaze.
    • PathGrind - Path-based dynamic analysis for 32-bit programs.
    • FuzzBALL - Symbolic execution tool built on the BitBlaze Vine component.
    • S2E - Symbolic execution platform supporting x86, x86-64, or ARM software stacks.
    • miasm - Reverse engineering framework. Includes symbolic execution.
    • pysymemu - Supports x86/x64 binaries.
    • BAP - Binary Analysis Platform provides a framework for writing program analysis tools.
    • angr - Python framework for analyzing binaries. Includes a symbolic execution tool.
    • Triton - Dynamic binary analysis platform that includes a dynamic symbolic execution tool.
    • manticore - Symbolic execution tool for binaries (x86, x86_64 and ARMV7) and Ethereum smart contract bytecode.

    Misc

    • Symbooglix - Symbolic execution tool for Boogie programs.

    博客:更好地理解符号执行

    1. 符号执行基础
      http://pwn4.fun/2017/03/20/符号执行基础/

    2. 符号执行:基础概念
      https://blog.csdn.net/wannafly1995/article/details/80842459

    3. 符号执行入门
      https://zhuanlan.zhihu.com/p/26927127

    4. 软件测试中的符号执行
      https://www.cnblogs.com/XBWer/p/9510884.html

    5. 符号执行——从入门到上高速
      https://www.colabug.com/4288118.html

    结束语

    2016年美国高等研究计划署(DAPRA)主办了自动网络攻防赛(CyberGrandChallenge),旨在建立实时自动化的网络防御系统,并且能够快速地应对大量新的攻击手法,以应对频发的网络攻击。符号执行在参赛队的自动攻防系统中起到了举足轻重的作用,被广泛应用在程序脆弱性的分析上,并涌现出了新的二进制符号执行分析框架,如圣塔芭芭拉大学Shellphish团队的angr和卡内基梅隆大学ForAllSecure团队的Mayhem。自动网络攻防赛的举办掀起了二进制符号执行的又一波热潮。

    虽然近年来各种符号执行优化技术不断被提出,符号执行的可用性和实用性也极大地提高了,但在现实软件分析应用中还面临着严峻的挑战,除了路径空间启发式搜索和约束求解之外,并行处理问题、内存建模和执行环境仿真等问题都有待进一步研究与改进。

    符号执行的另一发展方向是与Fuzzing技术相结合,以提高程序脆弱性检测的能力。微软研究机构在SAGE中就已经进行了这一尝试和探索,并成功将其应用在对Office和Windows等产品的错误检测上,也取得了显著的成果。2016年,Shellphish团队基于angr分析框架和AFL模糊测试器开发了Driller,用符号执行来增强模糊测试,为后续的研究提供了新思路。

    展开全文
  • 动态重定位执行过程

    千次阅读 2017-06-21 23:10:01
    ld-linux.so.2的_dl_runtime_resolve函数,这个函数解析出puts的绝对地址,回填到GOT[5]。 所有动态库函数在第一次...动态重定位执行过程 linux 动态链接器提供动态重位功能,所有外部函数只有调用时才做重定位
  • Java 动态调试技术原理及实践

    千次阅读 多人点赞 2019-11-07 19:55:19
    动态调试要解决的问题断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径。但断点调试会在断点位置停顿,使得整个应用停止响应。在线上停顿应用是致命的,动态...
  • Java下拼接执行动态SQL语句

    万次阅读 2015-10-30 09:57:30
    在实际业务中经常需要拼接动态SQL来完成复杂数据计算,网上各类技术论坛都有讨论,比如下面这些问题:  http://bbs.csdn.net/topics/390876591  http://bbs.csdn.net/topics/390981627  ...
  • mySql拼接动态SQL并执行

    万次阅读 2018-06-28 16:48:09
    1、之前写了接收动态存储过程返回值的文章,今天写一下拼接并执行动态sql语句的方法 2、具体SQL语句如下  set pSql = concat('update kqcard set ',vFingerIndex,' = \'', vFingerData, '\' , zkkqEnable = 1 ...
  • 但是考虑到最终会在多家保安公司上线,所以可能每家公司要求执行的定时器任务的执行周期是不会一样的,起初想着直接同意规定死一个执行周期的,后来为了让系统更加的具有灵活了(当然是项目更有卖点)。一开始想着...
  • Python 模块动态加载技术

    千次阅读 2016-04-02 23:54:43
    使用 exec 实现 Python 模块动态加载 该技术可以使用 python 语法的配置文件,并在系统运行过程中实现配置文件的更新 该技术也可以将 python 脚本作为业务逻辑动态加载到运行的系统中,实现业务逻辑在线更新
  • 动态网页技术

    千次阅读 热门讨论 2014-02-13 20:19:35
    1,动态网页与静态网页的最主要的区别? ——针对页面的访问请求,Web服务器在不同的条件下 返回给客户端的网页内容是否总是相同,例如:当浏览器访问Web服务器上某一个资源路劲的 时候,如果Web服务器返回的网页内容...
  • JVM中的动态追踪技术

    万次阅读 2020-08-11 17:55:53
    动态追踪技术 动态追踪技术是一个可以不用重启线上java项目来进行问题排查的技术,也叫Java Agent技术,可以利用它来构建一个附加的代理程序,用来协助检测性能,还可以替换一些现有功能,甚至JDK的一些类我们也能...
  • 浅谈动态追踪技术

    千次阅读 2019-04-18 18:17:45
    本文主要介绍了动态追踪技术,并举例说明动态追踪技术的应用。 身为一个SRE,工作中经常会遇到各种奇奇怪怪的服务异常问题。这些问题在staging(测试环境)没有发现,但放到真实的生产环境就会碰到,最关键的是...
  • 三种动态网页技术的简要分析

    万次阅读 2016-11-25 22:12:37
    动态网页可以根据用户的选择、点击、输入等操作而...1 ASP技术ASP技术是基于.NET平台的一种动态网页技术。它有非常强大的后台处理能力,但却有一些安全性、稳定性、跨平台性的问题。它的原理为:通过服务器端的解释器将
  • 程序动态切片技术研究

    千次阅读 2016-08-31 21:16:06
    动态程序切片主要是指在某个给定输入的条件下,源程序执行路径上所有对程序某条语句或兴趣点上的变量有影响的语句。 面向对象技术仍是目前软件开发方法的主流,其中封装、继承、多态、并发等特
  • WMI技术介绍和应用——执行方法

    千次阅读 2016-01-21 20:20:37
    本文将介绍WMI的另一种用法——执行方法。(转载请指明出于breaksoftware的csdn博客)  这块的内容在msdn中有详细的介绍,如果想看原版的可以参阅《Example: Calling a Provider Method》  本文将基于《WMI技术...
  • PB代码动态解析执行

    千次阅读 2009-10-11 20:52:00
    PB代码动态解析执行器 当你看到VB、VFP等开发语言提供的强大的宏执行功能,是不是很羡慕呢?当你寻遍PB的帮助、关于PB开发的书籍或网站而不可得的时候,是不是感到有一丝的遗憾?如果你看到这篇文章,你应该感到振奋...
  • 常用的4种动态网页技术

    万次阅读 2016-04-16 22:14:06
    1. 常用的4种动态网页技术 1.1. CGI CGI(Common Gateway Interface,公用网关接口)是较早用来建立动态网页的技术。当客户端向Web服务器上指定的CGI程序发出请求时,Web服务器会启动一个新的进 程执行某些CGI...
  • 代理分两种技术,一种是jdk代理(机制就是反射,只对接口操作),一种就是字节码操作技术。前者不能算技术,后者算是新的技术。...(一)jdk 动态代理: 1.定义业务逻辑 public interface Service { //
  • 用Mybatis+Spring框架,通过XML的编写和接口的编写,实现数据库的CRUD。...1.得到注入的Spring Bean(这个Bean是Mybatis通过JDK动态代理生成的)。 2.执行Bean方法(通过Bean里面的id找到具体的SQL,并执行)。
  • 动态网页技术基础

    千次阅读 2008-01-07 17:12:00
    内容提要 动态网站结构 动态网页特征 主要动态网页技术 1.动态网站结构?答:采用Web方式、实时动态交互等形式,将应用逻辑集中到服务器端;一般由浏览器、WEB服务器、应用服务器、数据库服务器组成;客户层的浏览器...
  • 动态编译技术在开源框架中的应用非常的广泛,现在市面上的插件化框架,热修复框架几乎都使用了动态编译技术,原理几乎都是在编译期间动态的在class文件中注入代码或者或修改。那就让我们来了解一下这高大上的技术吧...
  • 安卓APP动态调试技术

    千次阅读 2016-01-19 16:51:08
    本文将以安卓APP为例,来详细介绍一下移动APP动态调试技术。 0x01 调试环境搭建 1.1 安装JDK JAVA环境的搭建请自行查找资料,这里不做详述。 1.2 安装Android SDK 下载地址:...
  • 动态网站开发技术

    千次阅读 2015-09-06 17:57:39
    动态网站开发技术 目前,最常用的4种动态网页开发语言有ASP(Active Server Page)、ASP.NET(Active Server Page .NET)、JSP(Java Server Page)和PHP(Hypertext Preprocessor)。那么这4种程序各有什么优...
  • 动态网页技术对比分析

    千次阅读 2007-05-24 21:03:00
    目前,主流的动态网页技术主要有:ASP,PHP,CGI,JSP等,技术上各有特点。1、JSP与ASP/ASP.NET的比较 JSP与Microsoft的ASP技术非常相似。两者都提供在HTML代码中混合某种程序代码且由语言引擎解释执行程序代码的能力...
  • 4.1 TabPanel动态加载页面并执行脚本 知道extjs是很久以前的事情,但是一直没有机会用到。不怕大家笑话,直到上个星期准备用它了,这才开始接触,没想到一开始就碰到难题。TablePanel动态加载页面很简单的,...
  • 腾讯蓝鲸智云是一套基于PaaS的技术解决方案,提供了完善的前后台开发框架、调度引擎、公共组件等模块,帮助业务的产品和技术人员快速构建低成本、免运维的支撑工具和运营系统。 PaaS平台不仅将应用服务的运行和开发...
  • Android动态加载dex技术初探

    万次阅读 2016-02-25 00:19:02
    今天不忙,研究了下Android动态加载dex的技术,主要参考:  1、http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html  2、http://www.fengyoutian.com/web/single/13  好歹算是跑通了。下面把实现...
  • 摘要:电子邮件群发追踪是邮件群发的高级课题,本文尝试分析电子邮件群发追踪技术的实现思路,并在此技术上分析动态信息推送技术。电子邮件格式电子邮件格式包括纯文本(Plain Text)和HTML两种主要格式。纯文本电子...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 589,258
精华内容 235,703
关键字:

动态执行技术