范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

RustforLinux源码导读Ref引用计数容器

  引子
  2022 年,我们很可能会看到 Linux 内核中的实验性 Rust 编程语言支持成为主流。2021.12.6 早上发出了更新的补丁,介绍了在内核中处理 Rust 的初始支持和基础设施。
  这次更新的内容包括: 升级到了最新 Stable 编译器和 Rust 2021 edition 。因此可以摆脱了  const_fn_transmute  , const_panic  、 const_unreachable_unchecked  、 core_panic   和 try_reserve   这几个之前未稳定的特性。 自定义  core   和  alloc  。为  alloc   添加了更加模块化的选项,以便禁用一些他们不需要的功能: no_rc   和  no_sync  ,主要是为上游 Rust 项目添加。 更严格的代码、文档和新的  lint  。 抽象和驱动程序更新。添加了序列锁、电源管理回调的抽象,io 内存( readX  / writeX  )、irq 芯片和高级流处理程序,gpio 芯片(包括 irq 芯片)、设备、amba 设备和驱动程序以及证书。此外,也改进并简化了  Ref  ( refcount_t   支持)对象并用它替换了 Rust 的  Arc   的所有实例。完全地从  alloc   crate 中删除了  Arc   和  Rc  。
  从现在开始,Rust for linux 团队将开始定期提交补丁,每两周左右。
  除了来自 Arm、Google 和 Microsoft 的支持外,这次该团队又收到一封来自红帽的信:红帽对 Rust 用于内核的工作也非常感兴趣(There is interest in using Rust for kernel work that Red Hat is considering)。 v2 补丁:https://lore.kernel.org/lkml/20211206140313.5653-1-ojeda@kernel.org/ www.phoronix.com/scan.php?pa… kernel crate 文档 为什么需要引入Ref来代替Arc
  Rust for Linux 中这个  kernel   crate 中之前使用的是  Arc   ,但是现在换成了  Ref  。 通过查看相关PR rust: update Ref to use the kernel"s refcount_t ,可以了解其中主要有两点原因: 最大化利用现有的  C   代码 和 消除恐慌(Panic)。内核中已经有了引用计数的实现  refcount_t  ,而且它超过引用计数的阈值时,不是 Panic(abort) 而是返回最大值(饱和加法)。因为这个原因,也使用  RBTree  (红黑树) 替代了  BTreeMap  。 不需要弱引用。
  Arc 有一个 MAX_REFCOUNT 的限制,是   isize::MAX as usize   大小,引用计数加法超过该大小就会溢出然后发生Panic(abort)。
  所以最终实现的  Ref   与 Arc  的区别在于: Ref   是基于内核的  refcount_t   来支持的 它不支持 弱引用,所以大小减少了一半 当它超过阈值时,它使得引用计数饱和(saturating)而非中止(abort) 它不提供  get_mut   方法,所以引用计数对象是 Pin 的。 Ref源码分析
  接下来分析一下 Ref  的实现。 Ref结构体
  Ref   结构体定义如下: /// A reference-counted pointer to an instance of `T`. /// /// The reference count is incremented when new instances of [`Ref`] are created, and decremented /// when they are dropped. When the count reaches zero, the underlying `T` is also dropped. /// /// # Invariants /// /// The reference count on an instance of [`Ref`] is always non-zero. /// The object pointed to by [`Ref`] is always pinned. pub struct Ref {     ptr: NonNull>,     _p: PhantomData>, } 复制代码
  它维护一个不变量(Invariants):引用计数  Ref   总是一个非零的一个实例,并且被  Ref  引用的对象总是 Pin 的(不可移动)。
  该结构体中使用  NonNull  ,而非  *mut T  ,这里需要协变(covariant),而非不变(invariant)。可以参考下面示例: use std::ptr::NonNull;  struct Ref {     x: NonNull,     // x: *mut T, // 如果换成 *mut T,编译将不会通过 }  fn take<"a>(r: Ref<&"a u32>, y: &"a u32) {}  fn give() -> Ref<&"static u32> { todo!() }  fn test() {     let y = 1;     // 协变,能传入 Ref<&"a u32> 的函数take,也能接收 Ref<&"static u32> 类型的参数,因为 "static: "a ,能接受子类型,也能接受父类型     take(give(), &y);  } 复制代码
  NonNull   是  *mut T  的协变版本,并且也代表了非空指针,代表了引用计数对象总是非空的,因为当计数为零就会释放。
  而这里使用  PhatomData   则是为了 Drop 检查,此处表示 Ref 类型拥有  RefInner  ,当  Ref   被 Drop 的时候, RefInner  也能跟着被 Drop 。 RefInner结构体
  再来看  RefInner   结构体: #[repr(C)] struct RefInner {     refcount: Opaque,     data: T, } 复制代码
  RefInner   内部包含了内核中 C 语言实现的引用计数结构体  refcount_t  ,这里就是为了复用 C 代码。
  其中  Opaque   类型 是  kernel   crate 内置的专门为了和 C 打交道提供的一个包装类型,定义如下: pub struct Opaque(MaybeUninit>);  impl Opaque {     /// Creates a new opaque value.     pub fn new(value: T) -> Self {         Self(MaybeUninit::new(UnsafeCell::new(value)))     }      /// Creates an uninitialised value.     pub fn uninit() -> Self {         Self(MaybeUninit::uninit())     }      /// Returns a raw pointer to the opaque data.     pub fn get(&self) -> *mut T {         UnsafeCell::raw_get(self.0.as_ptr())     } } 复制代码
  Opaque 类型意味着永远都不需要 Rust 代码来解释的 FFi 对象。所以,为了使用内核中已经存在的引用计数结构体,这里用  Opaque  类型。 关于refcount_t
  Linux 内核中定义的  refcount_t   结构体定义如下:  // from: https://github.com/torvalds/linux/blob/master/tools/include/linux/refcount.h typedef struct refcount_struct { 	atomic_t refs; } refcount_t; 复制代码
  refcount_t   API的目标是为实现对象的引用计数器提供一个最小的API。虽然内部使用了原子操作,但一些  refcount_*()   和  atomic_*()   函数在内存顺序保证方面有很多不同。
  refcount_t   在2018年曾经发生过 引用计数溢出的安全漏洞,即,当引用计数达到最大值时,如果再加一,则引用计数就会归零。所以,此时引用的对象就会被错误释放。这样就变成了一个 UAF(use-after-free) 漏洞,容易被人利用。
  所以现在  refcount_t   被增加了引用计数检测: // from: https://github.com/torvalds/linux/blob/master/tools/include/linux/refcount.h#L69  static inline __refcount_check bool refcount_inc_not_zero(refcount_t *r) { 	unsigned int old, new, val = atomic_read(&r->refs);  	for (;;) { 		new = val + 1;  		if (!val) 			return false;  		if (unlikely(!new)) 			return true;  		old = atomic_cmpxchg_relaxed(&r->refs, val, new); 		if (old == val) 			break;  		val = old; 	}  	REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory. ");  	return true; } 复制代码
  在达到引用计数最大时采用饱和(saturated)加法,即,返回最大的值,而非零。注意,这里使用了 compare-and-swap  原子操作且并未提供内存顺序(使用relaxed)。 为Ref实现的一些 trait
  为了让  Ref   拥有一些类似于  Arc   的行为,所以为其实现一些内置 trait。 // This is to allow [`Ref`] (and variants) to be used as the type of `self`. impl core::ops::Receiver for Ref {}  // This is to allow [`RefBorrow`] (and variants) to be used as the type of `self`. impl core::ops::Receiver for RefBorrow<"_, T> {}  // This is to allow coercion from `Ref` to `Ref` if `T` can be converted to the // dynamically-sized type (DST) `U`. impl, U: ?Sized> core::ops::CoerceUnsized> for Ref {}  // This is to allow `Ref` to be dispatched on when `Ref` can be coerced into `Ref`. impl, U: ?Sized> core::ops::DispatchFromDyn> for Ref {}  // SAFETY: It is safe to send `Ref` to another thread when the underlying `T` is `Sync` because // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs // `T` to be `Send` because any thread that has a `Ref` may ultimately access `T` directly, for // example, when the reference count reaches zero and `T` is dropped. unsafe impl Send for Ref {}  // SAFETY: It is safe to send `&Ref` to another thread when the underlying `T` is `Sync` for // the same reason as above. `T` needs to be `Send` as well because a thread can clone a `&Ref` // into a `Ref`, which may lead to `T` being accessed by the same reasoning as above. unsafe impl Sync for Ref {} 复制代码
  从上面代码里看得出来,用到的 trait 有: core::ops::Receiver   : 是一个未稳定特性( receiver_trait   features),它表示一个结构体可以作为方法接收者,不需要 arbitrary_self_types   特性。标准库中一些智能指针实现了该trait,比如  Box  /  Arc   /  Rc   /  &T   /  Pin
  等。 core::ops::CoerceUnsized   :也是一个未稳定特性( coerce_unsized   features),它表示将 Size 类型转换为 DST 类型。 core::ops::DispatchFromDyn  : 同样是一个未稳定的特性( dispatch_from_dyn   features),它用于对象安全(动态安全 dyn safe)的检查。实现  DispatchFromDyn   的类型可以安全地用作对象安全方法中的 self 类型。 Send/Sync  ,是Rust 中稳定的特性,用于标记线程间可安全传递和共享的类型。
  现在为  Ref   实现了这些 trait,那么  Ref   也就拥有了相应的行为。基本上  Ref   的行为和  Arc   类似了,除了上面所说的那些区别。 引用计数管理
  因为  Ref   是复用内核 C 代码,所以对于引用计数的管理,只需要实现相应的 trait 即可。
  比如, Clone   时应该自增引用计数,而  Drop   时应该自减引用计数。所以,分别来看一下这两个实现。  // 实现 Clone trait impl Clone for Ref {     fn clone(&self) -> Self {         // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.         // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is         // safe to increment the refcount.         unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) };          // SAFETY: We just incremented the refcount. This increment is now owned by the new `Ref`.         unsafe { Self::from_inner(self.ptr) }     } } 复制代码
  实现  Clone   trait 很简单,直接通过  bindings::refcount_inc   来调用内核中  refcount_t   的自增方法  refcount_inc  即可。
  因为  refcount_inc   已经是有了引用计数溢出检测,使用饱和加法,所以不用担心归零。 // 实现 Drop trait impl Drop for Ref {     fn drop(&mut self) {         // SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot         // touch `refcount` after it"s decremented to a non-zero value because another thread/CPU         // may concurrently decrement it to zero and free it. It is ok to have a raw pointer to         // freed/invalid memory as long as it is never dereferenced.         let refcount = unsafe { self.ptr.as_ref() }.refcount.get();          // INVARIANT: If the refcount reaches zero, there are no other instances of `Ref`, and         // this instance is being dropped, so the broken invariant is not observable.         // SAFETY: Also by the type invariant, we are allowed to decrement the refcount.         let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };         if is_zero {             // The count reached zero, we must free the memory.              // SAFETY: This thread holds the only remaining reference to `self`, so it is safe to             // get a mutable reference to it.             let inner = unsafe { self.ptr.as_mut() };             let layout = Layout::for_value(inner);             // SAFETY: The value stored in inner is valid.             unsafe { core::ptr::drop_in_place(inner) };             // SAFETY: The pointer was initialised from the result of a call to `alloc`.             unsafe { dealloc(self.ptr.cast().as_ptr(), layout) };         }     } } 复制代码
  实现  Drop   trait,同样直接通过  bindings::refcount_dec_and_test   调用内核  refcount_dec_and_test   函数即可,该函数也包含了引用计数溢出检查。但是在引用计数归零的时候,需要释放内存。
  注意上面  Clone   和  Drop   这两个 trait 的实现,是 Unsafe Rust 抽象为 Safe Rust 的一个经典范例,主要是其中的 Safety  注释,考虑了安全边界,并且加以说明。 创建新的引用计数对象
  接下来需要关注  Ref   如何创建新的引用计数对象。 impl Ref {     /// Constructs a new reference counted instance of `T`.     pub fn try_new(contents: T) -> Result {         let layout = Layout::new::>();         // SAFETY: The layout size is guaranteed to be non-zero because `RefInner` contains the         // reference count.         let inner = NonNull::new(unsafe { alloc(layout) })             .ok_or(Error::ENOMEM)?             .cast::>();          // INVARIANT: The refcount is initialised to a non-zero value.         let value = RefInner {             // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1.             refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),             data: contents,         };         // SAFETY: `inner` is writable and properly aligned.         unsafe { inner.as_ptr().write(value) };          // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new         // `Ref` object.         Ok(unsafe { Self::from_inner(inner) })     } }  复制代码
  该  try_new   方法中使用  core::alloc::Layout   结构体来定义内存布局。
  通过  NonNull::new   和 自定义的  core::alloc::alloc   函数 来分配新的内存,并转换为  RefInner>   类型,并通过  bindings::REFCOUNT_INIT  调用内核 C 函数对其初始化为  1   。其中 自定义的  core::alloc   模块将来都会同步到  rust   core 中。
  其中  Error::ENOMEM  代表  OOM   错误。在  kernel/error.rs   中定义了很多内核错误码对应的错误。
  Linux 内核中使用整数定义了很多错误码,在 kernel crate 中,使用了 NewType 模式对其进行封装,而非直接使用整数错误码: macro_rules! declare_err {     ($err:tt) => {         pub const $err: Self = Error(-(bindings::$err as i32));     };     ($err:tt, $($doc:expr),+) => {         $(         #[doc = $doc]         )*         pub const $err: Self = Error(-(bindings::$err as i32));     }; }  #[derive(Clone, Copy, PartialEq, Eq)] pub struct Error(c_types::c_int);  impl Error {     declare_err!(EPERM, "Operation not permitted.");      declare_err!(ENOENT, "No such file or directory.");      declare_err!(ESRCH, "No such process.");      declare_err!(ENOMEM, "Out of memory.");      // ...  } 复制代码从已经存在的RefInner构造Ref
  在上面的  try_new   方法中看到,最后一步使用  from_inner   方法将一个裸指针构造为最终的  Ref  。并且它是一个内部方法,不是公开的 API。
  注意,它是一个 unsafe 的方法,因为需要调用者来确保 inner 的指针是有效且非空的,对于这一点其文档注释也写的比较清楚。 impl Ref {     /// Constructs a new [`Ref`] from an existing [`RefInner`].     ///     /// # Safety     ///     /// The caller must ensure that `inner` points to a valid location and has a non-zero reference     /// count, one of which will be owned by the new [`Ref`] instance.     unsafe fn from_inner(inner: NonNull>) -> Self {         // INVARIANT: By the safety requirements, the invariants hold.         Ref {             ptr: inner,             _p: PhantomData,         }     }  } 复制代码RefBorrow
  不存在对底层引用计数结构体的可变借用,但是存在一个不可变的借用,并且需要手动维护生命周期。 /// A borrowed [`Ref`] with manually-managed lifetime. /// /// # Invariants /// /// There are no mutable references to the underlying [`Ref`], and it remains valid for the lifetime /// of the [`RefBorrow`] instance. pub struct RefBorrow<"a, T: ?Sized + "a> {     inner: NonNull>,     _p: PhantomData<&"a ()>, }  impl Clone for RefBorrow<"_, T> {     fn clone(&self) -> Self {         *self     } }  impl Copy for RefBorrow<"_, T> {} 复制代码
  RefBorrow   结构体使用  PhantomData<&"a ()>   来持有生命周期参数,并为其实现 Copy trait,其行为和普通的不可变引用类似。
  然后为  Ref   实现一个  as_ref_borrow   方法即可从  Ref   得到  RefBorrow  。 impl Ref {      /// Returns a [`RefBorrow`] from the given [`Ref`].     ///     /// This is useful when the argument of a function call is a [`RefBorrow`] (e.g., in a method     /// receiver), but we have a [`Ref`] instead. Getting a [`RefBorrow`] is free when optimised.     #[inline]     pub fn as_ref_borrow(&self) -> RefBorrow<"_, T> {         // SAFETY: The constraint that lifetime of the shared reference must outlive that of         // the returned `RefBorrow` ensures that the object remains alive.         unsafe { RefBorrow::new(self.ptr) }     }  }  复制代码
  其实按 Rust 命名规范,此处  as_ref_borrow   改为  as_ref   更好。但是这里其实  as_ref   另有用处: impl AsRef for Ref {     fn as_ref(&self) -> &T {         // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is         // safe to dereference it.         unsafe { &self.ptr.as_ref().data }     } } 复制代码
  要通过  as_ref   方法从  Ref   得到  &T  。
  然后为  RefBorrow   实现  Deref   trait,也可以从  RefBorrow   拿到  &T  。 impl Deref for RefBorrow<"_, T> {     type Target = T;      fn deref(&self) -> &Self::Target {         // SAFETY: By the type invariant, the underlying object is still alive with no mutable         // references to it, so it is safe to create a shared reference.         unsafe { &self.inner.as_ref().data }     } } 复制代码唯一引用类型UniqueRef
  除了  Ref   之外,还实现了一个  UniqueRef   类型。顾名思义,该类型表示只有唯一一个引用计数的情况。 pub struct UniqueRef {     inner: Ref, }  impl UniqueRef {     /// Tries to allocate a new [`UniqueRef`] instance.     pub fn try_new(value: T) -> Result {         Ok(Self {             // INVARIANT: The newly-created object has a ref-count of 1.             inner: Ref::try_new(value)?,         })     }      /// Tries to allocate a new [`UniqueRef`] instance whose contents are not initialised yet.     pub fn try_new_uninit() -> Result>> {         Ok(UniqueRef::> {             // INVARIANT: The newly-created object has a ref-count of 1.             inner: Ref::try_new(MaybeUninit::uninit())?,         })     } } 复制代码
  没有为其实现  Clone   和  Drop   这两个 trait,所以它只能持有唯一一个引用。引入该类型也许可以为内核开发提供更多便利。 其他
  Ref   还实现了其他 trait,比如  From/TryFrom   ,可以从裸指针和  Ref  之间相互转换。
  一个值得注意的地方是: impl Ref {     /// Deconstructs a [`Ref`] object into a raw pointer.     ///     /// It can be reconstructed once via [`Ref::from_raw`].     pub fn into_raw(obj: Self) -> *const T {         let ret = &*obj as *const T;         core::mem::forget(obj);         ret     } } 复制代码
  将  Ref   转换为裸指针时,注意使用  core::mem::forget(obj)   避免调用  obj   的 Drop ,否则会让引用计数减少而引起问题。 小结
  从 Rust for Linux 源码中可以学习很多 Unsafe Rust 的相关技巧,尤其是和 C 语言打交道的一些比较好的实践。如果你感兴趣,还能学习 Linux 内核相关的一些内容,为将来是要 Rust 编写 Linux 内核驱动做一些准备。 最后
  如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑
  如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu不胜感激 !
  PHP学习手册: https://doc.crmeb.com
  技术交流论坛: https://q.crmeb.com

无穷六绝七翻身,拿着不动等轮动今日两市再度上涨,成交量连续第三天破万亿,北向资金持续流入。WIND全A指数已经是连续第五天上涨了,整个市场的氛围开始好起来。接下来可能会有两种走势一调整震荡一两天,然后加速上涨。一边吃面一边哭,泪水滴在碗里,没有开灯一前言没有经历过2011年重庆啤酒黑天鹅事件的人,可能看不懂这个标题。2011年12月7日,重庆啤酒黑天鹅事件爆发,引发连续跌停,股价大幅下挫。12月15日,在重庆啤酒经历了连续第四季度投资重点关注消费新能源车光伏和中证1000近期市场热点切换极其迅速,各路资金都在为四季度的投资布局。这段时间和机构牛散粉丝交流得比较多,对某些行业的观点或多或少也有些许的变化。这篇文章给大家谈一谈我下半年的投资思路。总的来白酒已成往事?大消费投资应当追投还是清仓?前言黎明前的曙光已经到来,建议关注新兴消费领域消费升级,后疫情复苏主线需要耐心等待。前段时间发了一篇A股长牛的消费行业,未来将何去何从,当时有些话没讲清楚,这篇文章算是一个补充,大新能源一枝独秀,大消费继续磨底今天整个盘面除了新能源就没一个能看的。上涨家数902,下跌家数3539,市场情绪极其低落。一大盘分析1新能源新能源今天是受到了昨晚2030年碳排放达峰行动方案的刺激。里面大部分内容别急着抄底猪周期深入浅出分析猪周期的投资逻辑前言从宏观角度出发,明年唯一可以确定的变量就是CPI的上涨,猪肉价格就是其导火索。相当于今年PPI上涨的原因上游原材料,妥妥的明年消费领域确定性极高的投资机会。加之周期行业底部买入聊聊军工港股有色地产,还有最近爆火的西部利得量化这是这个系列的最后一篇文章,这篇主要给大家讲一讲军工港股房地产有色金融地产等板块,再分析一下最近爆火的西部利得量化基金。一军工产业趋势向好,信息不透明是压制估值的核心先给大家复盘军白酒大跌,宁德时代再创新高今日市场的走势极其的怪异,一方面由于央行周末的一些表态,基本杜绝了货币政策进一步宽松的可能性,导致十年债大幅杀跌0。52。在这种情况下,按理说是会对成长风格产生极大的压制,但成长风经济滞涨,基建投资开始加速今天发布了8月份宏观经济数据。规模以上工业增加值同比增长5。3,预期5。8。18月固定资产投资同比增长8。9,预期9。1。18月房地产开发投资同比增长10。9,连续四个月下滑。8月政策传导新能源大涨,部分周期品逻辑已变,或可考虑离场昨天晚上印发了全面贯彻新发展理念做好碳达峰碳中和工作的意见。这是关于碳中和政策的最高文件,是反复提的1N框架中的那个1。这份文件一定要反复研读,看个十几遍,这对接下来的投资非常有帮煤炭钢铁有色板块盘整,四季度投资主线已出?今天市场的赚钱效应很差,上涨1367家,下跌2986家,反倒北向资金买了131亿。一大盘分析煤炭钢铁有色板块再度出现了大幅调整,动力煤期货也是再度封死跌停。目前看来上游顺周期可能要
这游戏手机,价格真TM香!还有4款刚刚,主打游戏性能旗舰,各方面配置直接拉满的iQOONeo6正式发布,堪称开黑神器。iQOONeo6采用三星120HzOLED直屏,E4发光材料,支持屏幕指纹解锁,搭载新骁龙8移动拒绝加入推特董事会,马斯克为何变卦?据外媒报道,距离马斯克宣布加入推特董事会不到一周,这位有钱任性的科技狂人又出现戏剧性反转。推特公司11日表示,马斯克已决定不加入该公司董事会。这一消息不仅在华尔街激起动荡,也再次引唯捷创芯上市首日大跌36,市值蒸发96亿依赖大厂背书,是机遇也是挑战4月12日,射频芯片企业唯捷创芯(天津)电子技术股份有限公司在科创板正式上市,本次共发行股票400800万股,发行价位66。6元股,不过当日开盘即破发,当日收盘报42。6元股,大跌摩托罗拉edgeS30冠军版今日开售此前,摩托罗拉推出的最新款旗舰配置手机edgeS30冠军版多次开售,但因为超强的性价比,并且将超大内存卖出了白菜价,一直供不应求。根据官方消息,该机将在今天上午10点再次开售,到手华擎推出3款4X4BOX5000系列迷你电脑配AMDRyzen5000U处理器华擎工业(ASRockIndustrial)今天推出了三款采用AMDZen3Ryzen5000U系列的4X4BOX5000系列迷你电脑,型号分别为4X4BOX5800U(配Ryze一加天玑8100机型现身GeekBenchAce系列要回归了?还有150W闪充近日,有关搭载天玑8000系列的一加机型开始有相关的爆料信息了,在海外已经有一款代号为PGKM10的一加机型出现在GeekBench测试网站上,该机搭载了天玑8100处理器。结合此三星新机渲染图被曝,双主摄加超大容量引人期待,屏幕使出新亮点如今很多制作旗舰手机的厂商也开始拼起了配置,但这也导致了很多手机机型出现了同质化的问题。为了解决这个问题,三星想出来的方法就是做巨屏手机。虽然手机屏幕大,就代表着体积会增大,从而导真我Q5系列官宣80W超速闪充,还有四大升级亮点4月13日消息,realme真我手机官方微博正式官宣了真我Q5系列采用80W超速闪充。realme副总裁徐起在微博中用一张图展示了这次真我Q5系列80W闪充的四大升级亮点,首先是峰软硬件全面变革凭实力OPPOFindN喜获两项2022年iF国际设计大奖根据近年来各大智能手机推出的机型看,折叠屏机型可以说已经成为了兵家必争之地,各大品牌不是发布了自家首款折叠屏手机产品,就是陆续发布了折叠屏手机的迭代产品,没有发布折叠屏手机的品牌也云闪付实力很强,为何就是火不起来?前几天曾经了解过云闪付,他们一直在招推广代理人员,个人觉得他们无论对于推广人员还是商户都是满满的套路国企一向很低调,他们会默默观察市场竞争,维持着微妙的平衡。在不得已的时候给出应急该主播涉嫌违规,正在整改中众所周知,直播现如今已经成为了一种新型的娱乐方式。但随着行业的发展,竞争压力的不断加大,有些主播就逐渐忘了本心,放飞自我。这不,近日虎牙直播平台就发生了一起低俗直播事件。据红星新闻