移动端浏览器的扫描二维码实现(vue-qrcode-reader与jsQR方式)
1. 实现功能
类似扫一扫的功能,自动识别到画面中的二维码并进行识别,也可以选择从相册中上传。
2. 涉及到的一些插件介绍
vue-qrcode-reader
一组用于检测和解码二维码的Vue.js组件
jsQR
一个纯粹的javascript二维码阅读库,该库接收原始图像,并将定位、提取和解析在其中找到的任何二维码。
zxing-wasm
ZXing-C++ WebAssembly 作为带有类型的 ES/CJS 模块。读/写 web、node、bun 和 deno 中的条形码。
2. vite项目配置本地开发使用https访问
安装basicSsl
pnpm i @vitejs/plugin-basic-ssl
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import basicSsl from '@vitejs/plugin-basic-ssl'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(), basicSsl()],server: {host: '0.0.0.0',https: true},resolve: {alias: {'@': path.resolve(__dirname, 'src')}}
})
3. 方式一:vue-qrcode-reader实现
npm install vue-qrcode-reader
🔍vue-qrcode-reader Api 介绍
<template><div><qrcode-streamclass="qrcode-wrap":torch="torch"v-memo="[torch]":constraints="selectedConstraints":track="paintBoundingBox"@error="onError"@detect="onDetect"@camera-on="onCameraReady"><div v-if="isSupportTorch" class="torch-wrap"><div class="torch" @click="() => (torch = !torch)"><div class="flash-light" v-if="torch"><MdiFlashlightOff style="width: 36px; height: 36px" /></div><div class="flash-light" v-else><MdiFlashlight style="width: 36px; height: 36px" /></div>{{ torch ? "关闭闪光灯" : "打开闪光灯" }}</div></div><div class="photo-wrap"><div class="photo" @click="handleOpenFile"><el-icon size="20"><PictureFilled /></el-icon></div><div class="color-[#fff]">相册</div></div></qrcode-stream></div>
</template>
<script setup lang="ts">
// https://gruhn.github.io/vue-qrcode-reader/api/QrcodeStream.html
import { QrcodeStream } from "vue-qrcode-reader";
import { PictureFilled } from "@element-plus/icons-vue";
import MdiFlashlight from "~icons/mdi/flashlight";
import MdiFlashlightOff from "~icons/mdi/flashlight-off";
import { ElMessage } from "element-plus";
import { fileOpen } from "browser-fs-access";
import _ from "lodash";const error = ref("");
const cameraIsReady = ref(false);
const isSupportTorch = ref(false); // 是否支持闪光灯
const torch = ref(false); // 闪光灯状态
// 相机配置选项: 'user'|'environment' (默认:environment)
const selectedConstraints = ref({ facingMode: "environment" });// 检测到二维码后绘制画布类型
function paintBoundingBox(detectedCodes: any, ctx: CanvasRenderingContext2D) {for (const detectedCode of detectedCodes) {const {boundingBox: { x, y, width, height },} = detectedCode;ctx.lineWidth = 2;ctx.strokeStyle = "#007bff";// 绘制边框矩形ctx.strokeRect(x, y, width, height);}
}async function onCameraReady(capabilities: any) {// NOTE: on iOS we can't invoke `enumerateDevices` before the user has given// camera access permission. `QrcodeStream` internally takes care of// requesting the permissions. The `camera-on` event should guarantee that this// has happened.try {isSupportTorch.value = !!capabilities.torch;cameraIsReady.value = true;error.value = "";} catch (error) {onError(error);cameraIsReady.value = false;}
}
// 错误提示
function onError(err: any) {error.value = `[${err.name}]: `;if (err.name === "NotAllowedError") {error.value += "you need to grant camera access permission";} else if (err.name === "NotFoundError") {error.value += "no camera on this device";} else if (err.name === "NotSupportedError") {error.value += "secure context required (HTTPS, localhost)";} else if (err.name === "NotReadableError") {error.value += "is the camera already in use?";} else if (err.name === "OverconstrainedError") {error.value += "installed cameras are not suitable";} else if (err.name === "StreamApiNotSupportedError") {error.value += "Stream API is not supported in this browser";} else if (err.name === "InsecureContextError") {error.value +="Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.";} else {error.value += err.message;}ElMessage.warning(error.value);
}
// 用户摄像头的流后
function onDetect(detectedCodes: any) {if (detectedCodes.length > 0) {onDecode(detectedCodes[0]?.rawValue);}
}const emit = defineEmits(["on-success"]);// 解码(交给父组件处理:进行网络请求)
function onDecode(text: string) {emit("on-success", text);
}
// 文件转成base64
const processFile = async (file: any) => {let reader = new FileReader();reader.readAsDataURL(file);reader.onload = (e) => {let base64String = e.target?.result as string ||'';// 此处可对该base64进行获取赋值传入后端, 如果有直接上传文件的接口就可以直接传文件onDecode(base64String)};
};
// 打开图片选择
async function handleOpenFile() {try {const file = await fileOpen({ mimeTypes: ["image/*"] }).catch(() => null);if (!file) return;// 计算文件的大小const fileSizeMb = _.round(file.size / 1024 / 1024, 2);// 文件大小不能超过 10MBconst limitSizeMb = 10;if (fileSizeMb > limitSizeMb) {return ElMessage.warning(`图片大小限制 ${limitSizeMb}MB`);}processFile(file)} catch (error) {console.log(`[log] - handleOpenUploadIcon - error:`, error);}
}
</script>
<style scoped>
.qrcode-wrap {position: fixed !important;top: 0;right: 0;bottom: 0;left: 0;width: 100vw;height: 100vh;z-index: 1 !important;background: rgba(0, 0, 0, 0.5);
}
.torch-wrap {width: 18.75rem;height: 12.5rem;position: fixed !important;left: 50%;top: 50%;transform: translate(-50%, -30%);z-index: 20;
}.torch {position: fixed;bottom: -6.25rem;left: 50%;transform: translateX(-50%);z-index: 20;color: #fff;display: flex;flex-direction: column;align-items: center;
}
.photo-wrap {position: fixed;bottom: 2.875rem;left: 2.875rem;display: flex;flex-direction: column;align-items: center;gap: 6px;
}.photo {height: 3.125rem;width: 3.125rem;background-color: rgba(250, 250, 250, 0.8);border-radius: 50%;display: grid;place-items: center;cursor: pointer;
}
</style>
browser-fs-access 这个包需要提前下载
pnpm i browser-fs-access
如果需要在离线的环境解析二维码,则需要使用zxing-wasm,在上面文件的js部分添加以下代码:
// 该文件由zxing-wasm项目构建而来
import wasmFile from './zxing_reader.wasm?url';// !为了离线加载
// https://github.com/gruhn/vue-qrcode-reader/issues/354
setZXingModuleOverrides({locateFile: (path: string, prefix: any) => {if (path.endsWith('.wasm')) {return wasmFile;}return prefix + path;},
});
✨ 该部分完整Demo代码在该文件夹下:Demo (二维码实现之vue-qrcode-reader)
4. 方式二:jsQR实现
🔍Canvas的基本介绍与使用
<template><div><div class="canvasBox"><div class="box"><div class="line"></div><div class="angle"></div></div><div v-if="isUseTorch" class="box2"><div class="track" @click="openTrack"><div class="flash-light" v-if="trackStatus"><MdiFlashlightOff style="width: 36px; height: 36px" /></div><div class="flash-light" v-else><MdiFlashlight style="width: 36px; height: 36px" /></div>{{ trackStatus ? "关闭闪光灯" : "打开闪光灯" }}</div></div><div class="photo-wrap"><div class="photo" @click="handleClickFile"><el-icon size="20"><inputclass="hide_file"ref="fileRef"type="file"accept="image/*;"@change="getFile"/><PictureFilled /></el-icon></div><div class="color-[#fff]">相册</div></div></div></div>
</template><script setup lang="ts">
// https://github.com/cozmo/jsQR
import jsQR from "jsqr";
import { PictureFilled } from "@element-plus/icons-vue";
import MdiFlashlight from "~icons/mdi/flashlight";
import MdiFlashlightOff from "~icons/mdi/flashlight-off";
import { ElMessage } from "element-plus";
import _ from "lodash";const props = withDefaults(defineProps<{// environment 后摄像头 user 前摄像头exact?: "environment" | "user";// whole 全屏 half 半屏size?: "whole" | "half";// 清晰度: fasle 正常 true 高清definition?: boolean;}>(),{exact: "environment",size: "whole",definition: false,}
);
const video = ref();
const canvas2d = ref();
const canvasWidth = ref(520);
const canvasHeight = ref(500);
const c = ref();
const track = ref();
const isUseTorch = ref(false);
const trackStatus = ref(false);
const fileRef = ref();onMounted(() => {const windowWidth = window.screen.availWidth;const windowHeight = window.screen.availHeight;canvasWidth.value = windowWidth;canvasHeight.value = windowHeight;nextTick(() => {video.value = document.createElement("video");c.value = document.createElement("canvas");c.value.id = "c";c.value.width = canvasWidth.value;c.value.height = canvasHeight.value;c.value.style.width = "100%";document.querySelector(".canvasBox")?.append(c.value);openScan();});
});onUnmounted(() => {closeCamera();
});
// 开始扫描
async function openScan() {try {let width = canvasHeight.value;width = props.size === "whole" ? width : width * 0.5;width = props.definition ? width * 1.6 : width;let height = canvasWidth.value;height = props.definition ? height * 1.6 : height;const videoParam = {audio: false,video: {facingMode: { exact: props.exact }, //强制使用摄像头类型width,height,},};// 获取用户摄像头的视频流const stream = await navigator.mediaDevices.getUserMedia(videoParam);if (stream) {video.value.srcObject = stream;video.value.setAttribute("playsinline", true); //内联播放video.value.play();requestAnimationFrame(tick);// 返回所有的媒体内容流的轨道列表track.value = stream.getVideoTracks()?.[0];setTimeout(() => {// 检测摄像头是否支持闪光灯isUseTorch.value = track.value.getCapabilities().torch || null;}, 500);}} catch (error) {ElMessage.warning("设备不支持,请检查是否允许摄像头权限!");console.log("获取本地设备(摄像头)---失败", error);}
}
function closeCamera() {if (video.value.srcObject) {video.value.srcObject.getTracks().forEach((track: any) => {track.stop();});}
}
function tick() {if (video.value.readyState === video.value.HAVE_ENOUGH_DATA) {canvasHeight.value = video.value.videoHeight;canvasWidth.value = video.value.videoWidth;c.value.width = canvasWidth.value;c.value.height = canvasHeight.value;if (canvas2d.value === undefined) {canvas2d.value = c.value.getContext("2d");}canvas2d.value.drawImage(video.value,0,0,canvasWidth.value,canvasHeight.value);const imageData = canvas2d.value.getImageData(0,0,canvasWidth.value,canvasHeight.value);// 解析二维码数据const code = jsQR(imageData.data, imageData.width, imageData.height, {inversionAttempts: "dontInvert",});if (!_.isEmpty(code)) {drawLine(code.location.topLeftCorner,code.location.topRightCorner,"#FF3B58");drawLine(code.location.topRightCorner,code.location.bottomRightCorner,"#FF3B58");drawLine(code.location.bottomRightCorner,code.location.bottomLeftCorner,"#FF3B58");drawLine(code.location.bottomLeftCorner,code.location.topLeftCorner,"#FF3B58");if (code.data) {getData(code.data);}}}requestAnimationFrame(tick);
}
function drawLine(begin: any, end: any, color: string) {canvas2d.value.beginPath();canvas2d.value.moveTo(begin.x, begin.y);canvas2d.value.lineTo(end.x, end.y);canvas2d.value.lineWidth = 4;canvas2d.value.strokeStyle = color;canvas2d.value.stroke();
}
const emit = defineEmits(["on-success"]);function getData(data: string) {emit("on-success", data);closeCamera();
}function openTrack() {trackStatus.value = !trackStatus.value;track.value.applyConstraints({advanced: [{ torch: trackStatus.value }],});
}
const handleClickFile = () => {fileRef.value.click();
};
const getFile = (e: any) => {const file = e.target.files[0];emit("on-success", file);closeCamera();
};
</script><style scoped>
.flash-light {display: grid;place-content: center;margin-bottom: 6px;
}.photo-wrap {position: fixed;bottom: 2.875rem;left: 2.875rem;display: flex;flex-direction: column;align-items: center;gap: 6px;
}.photo {height: 3.125rem;width: 3.125rem;background-color: rgba(250, 250, 250, 0.8);border-radius: 50%;display: grid;place-items: center;cursor: pointer;
}.hide_file {display: none;
}page {background-color: #333333;
}.canvasBox {width: 100vw;position: relative;top: 0;bottom: 0;left: 0;right: 0;background-image: linear-gradient(0deg,transparent 24%,rgba(32, 255, 77, 0.1) 25%,rgba(32, 255, 77, 0.1) 26%,transparent 27%,transparent 74%,rgba(32, 255, 77, 0.1) 75%,rgba(32, 255, 77, 0.1) 76%,transparent 77%,transparent),linear-gradient(90deg,transparent 24%,rgba(32, 255, 77, 0.1) 25%,rgba(32, 255, 77, 0.1) 26%,transparent 27%,transparent 74%,rgba(32, 255, 77, 0.1) 75%,rgba(32, 255, 77, 0.1) 76%,transparent 77%,transparent);background-size: 3rem 3rem;background-position: -1rem -1rem;z-index: 10;background-color: #1110;
}.box {width: 11.9375rem;height: 11.9375rem;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -80%);overflow: hidden;border: 0.1rem solid rgba(0, 255, 51, 0.2);z-index: 11;
}.line {height: calc(100% - 2px);width: 100%;background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);border-bottom: 3px solid #00ff33;transform: translateY(-100%);animation: radar-beam 2s infinite alternate;animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);animation-delay: 1.4s;
}.box:after,
.box:before,
.angle:after,
.angle:before {content: "";display: block;position: absolute;width: 3vw;height: 3vw;z-index: 12;border: 0.2rem solid transparent;
}.box:after,
.box:before {top: 0;border-top-color: #00ff33;
}.angle:after,
.angle:before {bottom: 0;border-bottom-color: #00ff33;
}.box:before,
.angle:before {left: 0;border-left-color: #00ff33;
}.box:after,
.angle:after {right: 0;border-right-color: #00ff33;
}@keyframes radar-beam {0% {transform: translateY(-100%);}100% {transform: translateY(0);}
}.box2 {width: 18.75rem;height: 12.5rem;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -80%);z-index: 20;
}.track {position: absolute;bottom: -6.25rem;left: 50%;transform: translateX(-50%);z-index: 20;color: #fff;display: flex;flex-direction: column;align-items: center;
}
</style>
✨该部分完整Demo代码在该文件夹下:Demo (二维码实现之jsQR)
5. 总结
方式一结合vue-qrcode-reade
r的封装性更强且识别二维码速度更快。
方式二接近了vue-qrcode-reader
的底层实现过程。
实际项目开发中更推荐方式一,兼容性与稳定性会更好些。
相关文章:

移动端浏览器的扫描二维码实现(vue-qrcode-reader与jsQR方式)
1. 实现功能 类似扫一扫的功能,自动识别到画面中的二维码并进行识别,也可以选择从相册中上传。 2. 涉及到的一些插件介绍 vue-qrcode-reader 一组用于检测和解码二维码的Vue.js组件 jsQR 一个纯粹的javascript二维码阅读库,该库接收原始…...

android中调用onnxruntime框架
创建空白项目 安装Android Studio及创建空白项目参考:【安卓Java原生开发学习记录】一、安卓开发环境的搭建与HelloWorld(详细图文解释)_安卓原生开发-CSDN博客 切记:build configuration language 一定选择Groovy!官…...

【机器学习】与【数据挖掘】技术下【C++】驱动的【嵌入式】智能系统优化
目录 一、嵌入式系统简介 二、C在嵌入式系统中的优势 三、机器学习在嵌入式系统中的挑战 四、C实现机器学习模型的基本步骤 五、实例分析:使用C在嵌入式系统中实现手写数字识别 1. 数据准备 2. 模型训练与压缩 3. 模型部署 六、优化与分析 1. 模型优化 模…...

Apollo9.0 PNC源码学习之Control模块(二)
前面文章:Apollo9.0 PNC源码学习之Control模块(一) 本文将对具体控制器以及原理做一个剖析 1 PID控制器 1.1 PID理论基础 如下图所示,PID各参数(Kp,Ki,Kd)的作用: 任何闭环控制系统的首要任务是要稳、准、快的响…...

直线度测量仪发展历程!
直线度测量仪的发展历程可以概括为以下几个关键阶段: 拉钢丝法: 早期直线度测量的简单直观方法,利用钢丝受重力自然下垂的原理来测量直线度误差。 随着机械设备的大型化和测量精度要求的提高,该方法逐渐无法满足要求,正…...

09-spring的bean创建流程(一)
文章目录 spring中bean的创建流程finishBeanFactoryInitialization(beanFactory)beanFactory.preInstantiateSingletons();getMergedLocalBeanDefinition(beanName);流程实现FactoryBean接口,里面的对象实例化过程 spring中bean的创建流程 finishBeanFactoryInitialization(be…...
spring中基于setting和构造器的注入方式
Spring中可以通过setting和构造器两种方式进行依赖注入。 1.基于setting的注入方式(Setter Injection): 实现方式:在类中添加对应的属性以及对应的setter方法,在配置文件中使用<property>元素进行注入。 示例代码…...
爬虫基本原理?介绍|实现|问题解决
爬虫基本原理: 模拟用户行为: 网络爬虫(Web Crawler)是一种自动化的程序,它模拟人类用户访问网站的方式,通过发送HTTP/HTTPS请求到服务器以获取网页内容。 请求与响应: 爬虫首先构建并发送带有…...
DevOps的原理及应用详解(六)
本系列文章简介: 在当今快速变化的商业环境中,企业对于软件交付的速度、质量和安全性要求日益提高。传统的软件开发和运维模式已经难以满足这些需求,因此,DevOps(Development和Operations的组合)应运而生&a…...

手撸 串口交互命令行 及 AT应用层协议解析框架
在嵌入式系统开发中,命令行接口(CLI)和AT命令解析是常见的需求。CLI提供了方便的调试接口,而AT命令则常用于模块间的通信控制。本文将介绍如何手动实现一个串口交互的命令行及AT应用层协议解析框架,适用于FreeRTOS系统…...
Redis几种部署模式介绍
Redis 提供了几种不同的部署模式,以满足不同的使用场景和可用性需求。这些模式包括单机模式、主从复制、哨兵模式和集群模式。下面我将简要介绍每种模式的特点和用途: 单机模式: 描述:单个 Redis 服务器实例运行在一台机器上&…...

【STM32HAL库学习】定时器功能、时钟以及各种模式理解
一、文章目的 记录自己从学习了定时器理论->代码实现使用定时->查询数据手册,加深了对定时器的理解以及该过程遇到了的一些不清楚的知识。 上图为参考手册里通用定时器框图,关于定时器各种情况的工作都在上面了,在理论学习和实际应用后…...
3588麒麟系统硬解码实战
目录 安装rockchip-mpp deb 查找头文件 .pro文件添加 检查库是否已安装 error: stdlib.h: No such file or directory ffmpeg 查找ffmpeg路径: 查找FFmpeg库和头文件的位置 使用pkg-config工具查找FFmpeg路径 ok的ffmpeg配置: ffmpeg查看是否支持libx264 ffmpeg …...
十二 nginx中location重写和匹配规则
十二 location匹配规则 ^~ ~ ~* !~ !~* /a / 内部服务跳转 十三 nginx地址重写rewrite if rewrite set return 13.1 if 应用环境 server location -x 文件是否可执行 $args $document_rot $host $limit_rate $remote_addr $server_name $document_uri if …...
python的视频处理FFmpeg库使用
FFmpeg 是一个强大的多媒体处理工具,用于录制、转换和流式传输音频和视频。它支持几乎所有的音频和视频格式,并且可以在各种平台上运行。FFmpeg 在 Python 中的使用可以通过调用其命令行工具或使用专门的库如 ffmpeg-python。以下是详细介绍如何在 Python 中使用 FFmpeg,包括…...

接口测试时, 数据Mock为何如此重要?
一、为什么要mock 工作中遇到以下问题,我们可以使用mock解决: 1、无法控制第三方系统某接口的返回,返回的数据不满足要求 2、某依赖系统还未开发完成,就需要对被测系统进行测试 3、有些系统不支持重复请求,或有访问…...
未授权与绕过漏洞
1、Laravel Framework 11 - Credential Leakage(CVE-2024-29291)认证泄漏 导航这个路径storage/logs/laravel.log搜索以下信息: PDO->__construct(mysql:host 2、 Flowise 1.6.5 - Authentication Bypass(CVE-2024-31621&am…...
云原生周刊:Kubernetes 十周年 | 2024.6.11
开源项目推荐 Kubernetes Goat Kubernetes Goat 是一个故意设计成有漏洞的 Kubernetes 集群环境,旨在通过交互式实践场地来学习并练习 Kubernetes 安全性。 kube-state-metrics (KSM) kube-state-metrics 是一个用于收集 Kubernetes 集群状态信息的开源项目&…...

ClickHouse内幕(1)数据存储与过滤机制
本文主要讲述ClickHouse中的数据存储结构,包括文件组织结构和索引结构,以及建立在其基础上的数据过滤机制,从Part裁剪到Mark裁剪,最后到基于SIMD的行过滤机制。 数据过滤机制实质上是构建在数据存储格式之上的算法,所…...
1.Mongodb 介绍及部署
MongoDB 是一个开源的文档导向数据库,采用NoSQL(非关系型数据库)的设计理念。MongoDB是一个基于分布式文件存储的数据库。 分布式文件存储是一种将文件数据分布式的存储在多台计算机上。MongoDB是一款强大的文档导向数据库,适合处…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...